Authoring

Creating Integrations

Integrations add files, dependencies, and code hooks to generated projects.

Quick Start

sh
# 1. Create base project
tanstack create my-integration-dev -y

# 2. Add your code
#    - src/integrations/my-feature/
#    - src/routes/demo/my-feature.tsx
#    - Update package.json

# 3. Extract integration
tanstack integration init

# 4. Edit .integration/info.json

# 5. Compile
tanstack integration compile

# 6. Test
tanstack create test --integrations my-feature --integrations-path ./.integration

Structure

my-integration/
├── info.json        # Metadata (required)
├── package.json     # Dependencies (optional)
└── assets/          # Files to copy
    └── src/
        ├── integrations/my-feature/
        └── routes/demo/my-feature.tsx

info.json

Required fields:

json
{
  "name": "My Feature",
  "description": "What it does",
  "type": "integration",
  "phase": "integration",
  "category": "tooling",
  "modes": ["file-router"]
}
FieldValues
typeintegration, toolchain, deployment, example
phasesetup, integration, example
categorytanstack, auth, database, orm, deploy, tooling, monitoring, api, i18n, cms, other

Optional fields:

json
{
  "dependsOn": ["tanstack-query"],
  "conflicts": ["other-feature"],
  "envVars": [{ "name": "API_KEY", "description": "...", "required": true }],
  "gitignorePatterns": ["*.cache"]
}

Hooks

Inject code into generated projects:

json
{
  "hooks": [
    {
      "type": "root-provider",
      "jsName": "MyProvider",
      "path": "src/integrations/my-feature/provider.tsx"
    }
  ]
}
TypeLocationUse
root-providerWraps app in __root.tsxContext providers
vite-pluginvite.config.tsVite plugins
devtoolsAfter app in __root.tsxDevtools
entry-cliententry-client.tsxClient init

Demo Routes

json
{
  "routes": [
    {
      "url": "/demo/my-feature",
      "name": "My Feature Demo",
      "path": "src/routes/demo/my-feature.tsx"
    }
  ]
}

Integration Options

Let users configure the integration:

json
{
  "options": {
    "database": {
      "type": "select",
      "label": "Database",
      "options": [
        { "value": "postgres", "label": "PostgreSQL" },
        { "value": "sqlite", "label": "SQLite" }
      ],
      "default": "postgres"
    }
  }
}

Access in EJS templates:

ejs
<% if (integrationOption['my-feature']?.database === 'postgres') { %>
// PostgreSQL code
<% } %>

EJS Templates

Files ending in .ejs are processed. Available variables:

VariableTypeDescription
projectNamestringProject name
typescriptbooleanTS enabled
tailwindbooleanTailwind enabled
integrationEnabledobject{ [id]: boolean }
integrationOptionobject{ [id]: options }

File patterns:

PatternResult
file.tsCopied as-is
file.ts.ejsEJS processed
_dot_gitignoreBecomes .gitignore
file.ts.appendAppended to existing

Distribution

Host on GitHub or npm, then:

sh
tanstack create my-app --integrations-path ./path/to/integrations

To add to official catalog: PR to integrations/ folder.