Bootstrapping a site
The bootstrap:site command sets up a fully-wired TwoTaps Next.js site with one command. It clones the official boilerplate, configures your environment, generates TypeScript types from your schemas, and scaffolds stub components for every block — so you can start building instead of plumbing.
Prerequisites
Before running the command you need:
- Git in your
PATH(used to clone the boilerplate) - Yarn in your
PATH(the boilerplate uses Yarn) - A TwoTaps API token — see Generating an API token below
- Your schema set identifier — either the numeric wrapper ID or the combination of organisation name + schema set name
Generating an API token
- Open your TwoTaps administration panel
- Navigate to API Token:
/administration/api-token?organisationId=YOUR_ORG_ID - Click Generate New Token and copy the result
Store the token securely. Never commit it to source control. Use an environment variable or a secrets manager.
Quick start
Export your API token and run the command:
export TWO_TAPS_API_TOKEN=your_api_token_here
npx twotaps bootstrap:site \
--ttGraphqlUrl https://api-lb-prod.twotaps.io/graphql \
--destinationPath ./my-site \
--sitePublicHost https://www.my-site.com \
--orgName "Acme Corp" \
--schemaWrapperName "My Schema Set"Or, if you know your numeric schema wrapper ID:
export TWO_TAPS_API_TOKEN=your_api_token_here
npx twotaps bootstrap:site \
--ttGraphqlUrl https://api-lb-prod.twotaps.io/graphql \
--destinationPath ./my-site \
--sitePublicHost https://www.my-site.com \
--schemaWrapperId 123Interactive mode
Any omitted required flag triggers an interactive prompt. You can run the command with no flags and answer each question:
export TWO_TAPS_API_TOKEN=your_api_token_here
npx twotaps bootstrap:site
# TwoTaps GraphQL URL: https://api-lb-prod.twotaps.io/graphql
# Schema wrapper ID (optional):
# Organisation name (required if wrapper ID not provided): Acme Corp
# Schema wrapper name (required if wrapper ID not provided): My Schema Set
# Site public host: https://www.acme.com
# Site base path (optional):
# Destination path: ./acme-site
# Boilerplate repository [https://github.com/ltnetwork/twotaps-boilerplate-nextjs.git]:--orgName / --schemaWrapperName and --schemaWrapperId are mutually exclusive. Provide one
set or the other, not both.
Step-by-step walkthrough
Set your API token
The CLI reads authentication credentials from the TWO_TAPS_API_TOKEN environment variable:
export TWO_TAPS_API_TOKEN=your_api_token_hereFor persistent use, add this to your shell profile (.zshrc, .bashrc, etc.) or use a .env file in your shell
session.
Choose how to identify your schema set
You can identify the target schema set in two ways:
Option A — by schema wrapper ID (fastest)
Find the ID in the TwoTaps admin UI under Schema Sets. The numeric ID appears in the URL:
/administration/schema-sets?organisationId=42 → schema wrapper detail page shows its ID.
--schemaWrapperId 123Option B — by organisation name + schema set name
Use the exact names as they appear in TwoTaps (case-insensitive match):
--orgName "Acme Corp" \
--schemaWrapperName "My Schema Set"Run the command
npx twotaps bootstrap:site \
--ttGraphqlUrl https://api-lb-prod.twotaps.io/graphql \
--destinationPath ./acme-site \
--sitePublicHost https://www.acme.com \
--orgName "Acme Corp" \
--schemaWrapperName "My Schema Set"You’ll see progress output as each step completes:
Cloning boilerplate into /path/to/acme-site...
Removing sample boilerplate components...
Creating .env from .env-example...
Running yarn install to setup dependencies...
Generating schema types...
SDL schema generated at /path/to/acme-site/types.ts, extracting interfaces...
Retrieved 12 block schemas from GraphQL API, scaffolding components...
Bootstrap complete at /path/to/acme-site
Created 12 componentsExplore the generated project
After the command completes, your project looks like this:
- .env
- .env-example
- types.ts
- index.ts
- HeroBlock.tsx
- LocationDetails.tsx
- ContactFormBlock.tsx
- ...
- package.json
- next.config.js
How it works under the hood
1. Boilerplate cloning
The CLI clones the official boilerplate repository (https://github.com/ltnetwork/twotaps-boilerplate-nextjs.git by default).
2. Environment setup
The generated .env file has three values pre-populated from your command flags:
NEXT_PUBLIC_GRAPHQL_URL="https://api-lb-prod.twotaps.io/graphql"
NEXT_PUBLIC_HOST="https://www.acme.com"
NEXT_PUBLIC_BASE_PATH="" # empty unless --siteBasePath is provided3. Schema type generation
The CLI calls the TwoTaps schema-builder endpoint (derived from your GraphQL URL) and writes all
TypeScript interfaces to types.ts in the project root. Every schema in your schema set gets a
corresponding exported interface:
// types.ts (generated — do not edit by hand)
export interface HeroBlock {
title: string;
subtitle?: string;
backgroundImage: TTImage;
}
export interface LocationDetails {
city: string;
address: string;
coords: TTGMBLocation;
}
export interface ContactFormBlock {
formId: number;
heading?: string;
}
// ...Built-in TwoTaps types (TTImage, TTLink, TTForm, etc.) are excluded from component
scaffolding — they are utility types, not page-level block components.
4. Component scaffolding
For each Block-type schema in your schema set, the CLI generates a stub component in
src/components/. The component is typed against the matching interface from types.ts:
// src/components/HeroBlock.tsx (generated stub)
import type { HeroBlock } from '../../types';
interface HeroBlockProps extends HeroBlock {}
export default function HeroBlock(props: HeroBlockProps) {
return <div></div>;
}You fill in the rendering logic. The type information is already wired up — TypeScript will catch any property name typos or missing fields immediately.
5. Component wiring (src/components/index.ts)
The final step writes src/components/index.ts with a NEXT_COMPONENTS map that connects schema
block names (as returned by TwoTaps) to their corresponding React components:
// src/components/index.ts (generated — regenerate with bootstrap:site)
'use client';
import ContactFormBlock from './ContactFormBlock';
import HeroBlock from './HeroBlock';
import LocationDetails from './LocationDetails';
export const NEXT_COMPONENTS = {
contact_form_block: ContactFormBlock,
hero_block: HeroBlock,
location_details: LocationDetails,
};The boilerplate’s block renderer reads from NEXT_COMPONENTS to resolve the right component for
each revision schema block at runtime.
All CLI options
| Flag | Type | Required | Description |
|---|---|---|---|
--ttGraphqlUrl | string | Yes (or prompted) | TwoTaps GraphQL endpoint, e.g. https://api-lb-prod.twotaps.io/graphql |
--destinationPath | string | Yes (or prompted) | Target directory for the new project |
--sitePublicHost | string | Yes (or prompted) | Canonical domain, e.g. https://www.my-site.com (sets NEXT_PUBLIC_HOST) |
--schemaWrapperId | string | Required unless orgName/schemaWrapperName is provided | Numeric schema set ID — mutually exclusive with --orgName/--schemaWrapperName |
--orgName | string | Required unless schemaWrapperId is provided | Organisation name (case-insensitive) |
--schemaWrapperName | string | Required unless schemaWrapperId is provided | Schema set name within the organisation (case-insensitive) |
--siteBasePath | string | No | Sub-path if the site is served under a path prefix, e.g. /us (sets NEXT_PUBLIC_BASE_PATH) |
--twoTapsHost | string | No | Override the API host for schema-builder calls. Derived from --ttGraphqlUrl if omitted. |
--boilerplateRepo | string | No | Custom boilerplate Git URL or local path. Defaults to the official TwoTaps Next.js boilerplate. |
After bootstrapping
Start the development server
cd acme-site
yarn devYour site will be available at http://localhost:3000. Pages are fetched from TwoTaps at request
time using the GraphQL URL in .env.
Implement your components
Open any generated stub and replace the empty <div> with real markup. The props are fully typed
via the interface from types.ts:
// src/components/HeroBlock.tsx
import type { HeroBlock } from '../../types';
interface HeroBlockProps extends HeroBlock {}
export default function HeroBlock({ title, subtitle, backgroundImage }: HeroBlockProps) {
return (
<section
style={{ backgroundImage: `url(${backgroundImage.url})` }}
aria-label={backgroundImage.alt}
>
<h1>{title}</h1>
{subtitle && <p>{subtitle}</p>}
</section>
);
}Regenerating types after schema changes
When you add or update schemas in TwoTaps, regenerate types.ts using the generate:sdl command:
export TWO_TAPS_API_TOKEN=your_api_token_here
npx twotaps generate:sdl \
--twoTapsHost https://api-lb-prod.twotaps.io \
--orgName "Acme Corp" \
--schemaWrapperName "My Schema Set"Re-running bootstrap:site will refuse to overwrite a non-empty destination directory. Use
generate:sdl to update types.ts in an existing project.
Using a custom boilerplate
You can point the bootstrapper at your own boilerplate repository:
npx twotaps bootstrap:site \
--ttGraphqlUrl https://api-lb-prod.twotaps.io/graphql \
--destinationPath ./acme-site \
--sitePublicHost https://www.acme.com \
--schemaWrapperId 123 \
--boilerplateRepo https://github.com/your-org/your-boilerplate.gitYour boilerplate must contain:
- A
.env-examplefile withNEXT_PUBLIC_GRAPHQL_URL,NEXT_PUBLIC_HOST, andNEXT_PUBLIC_BASE_PATHentries - A
src/components/directory
Troubleshooting
TWO_TAPS_API_TOKEN environment variable is not set
Export the variable before running the command:
export TWO_TAPS_API_TOKEN=your_api_token_hereDestination directory is not empty
The target directory must not exist (or must be empty). Choose a new path or remove the existing directory:
rm -rf ./acme-site
npx twotaps bootstrap:site ...Organisation not found by name
Double-check that the --orgName value matches the exact name in TwoTaps (the comparison is
case-insensitive but the name must be an exact word match). Use --schemaWrapperId if you’re
unsure.
GraphQL request failed: 401
Your API token is invalid or expired. Generate a new one from the TwoTaps administration panel.
git: command not found / yarn: command not found
Install the missing tool and ensure it is on your PATH before running bootstrap:site.
Related documentation
- Generating schema types — regenerate
types.tsin an existing project - Schemas overview — deep dive into schema architecture and the site-utils packages