How to Set Up a Local Development Environment for OpenSEO Using TanStack Start

Setting up OpenSEO locally requires Node 20+, Corepack for pnpm management, DataForSEO API credentials, and running pnpm dev:agents after installing dependencies and migrating the SQLite database.

OpenSEO is a full-stack SEO application built on TanStack Start, a zero-config framework combining Vite, React 19, and TanStack Router. This guide provides the exact steps to set up a local development environment for OpenSEO using TanStack Start, including architecture details from the source code and the specific commands needed to run the Cloudflare Workers-based development server.

Prerequisites

Before cloning the repository, ensure your system meets the runtime requirements defined in [docs/LOCAL_DEVELOPMENT.md](https://github.com/every-app/open-seo/blob/main/docs/LOCAL_DEVELOPMENT.md).

Node.js and Corepack

You need Node.js 20 or higher installed on your machine. The project uses Corepack (bundled with Node.js 24+) to manage the exact pnpm version declared in package.json.

Run the following command to enable Corepack:

corepack enable

This ensures the pnpm binary matches the packageManager field (pnpm@10.30.1). Using a globally installed pnpm version that differs from the lockfile will cause installation errors.

DataForSEO Account

Every API request in OpenSEO requires DataForSEO credentials. You must create an account and generate API keys, as these are not optional for local development.

Install Dependencies and Configure the Environment

Once prerequisites are met, install the project dependencies and prepare the local configuration.

Lockfile Installation

Navigate to the project root and install dependencies using the frozen lockfile:

pnpm install --frozen-lockfile

This command respects the exact versions defined in pnpm-lock.yaml, ensuring consistency across environments.

Database Migration

OpenSEO uses SQLite D1 as the default local database. Initialize it with:

pnpm run db:migrate:local

This creates the local database file and applies all existing schema migrations. For PostgreSQL support (optional), see [docs/LOCAL_POSTGRES.md](https://github.com/every-app/open-seo/blob/main/docs/LOCAL_POSTGRES.md).

Environment Variables

Copy the example environment file and configure your local secrets:

cp .env.example .env.local

Edit .env.local to include these required variables:

  • DATAFORSEO_API_KEY: Base64-encoded login:password string (e.g., printf '%s' 'mylogin:mysecret' | base64)
  • AUTH_MODE: Set to local_noauth to bypass Cloudflare Access and inject a dummy admin@localhost user

Start the Development Server

OpenSEO provides two development scripts in package.json:

Script Purpose
pnpm run dev Starts Vite on port 4322 (standard mode)
pnpm dev:agents Starts Vite through portless with logging to .logs/dev-server.log (recommended for AI agents and worktrees)

Run the recommended command:

mkdir -p .logs && pnpm dev:agents

The application launches at http://open-seo.localhost:1355. When using git worktrees, portless automatically prefixes the branch name (e.g., http://feature-x.open-seo.localhost:1355).

TanStack Start Architecture

Understanding how TanStack Start powers OpenSEO helps debug configuration issues and extend the application.

Vite Configuration

In [web/vite.config.ts](https://github.com/every-app/open-seo/blob/main/web/vite.config.ts), the tanstackStart plugin generates the server entry and enables prerendering:

import { tanstackStart } from "@tanstack/react-start/plugin/vite";

export default defineConfig({
  plugins: [
    tanstackStart({
      prerender: {
        enabled: true,
        filter: ({ path }) => !/\.pdf(?:[?#]|$)/i.test(path),
      },
    }),
    react(),
  ],
});

The plugin generates @tanstack/react-start/server-entry and wires up the TanStack Router. The prerender configuration excludes PDF routes from static generation.

Worker Entry Point

The web/wrangler.jsonc file declares the Cloudflare Workers configuration:

{
  "main": "@tanstack/react-start/server-entry",
  "assets": {
    "directory": "./dist/client",
    "html_handling": "drop-trailing-slash"
  },
  "kv_namespaces": [{ "binding": "BACKLINK_CHECK_KV", "id": "..." }],
  "ratelimits": [{ "name": "BACKLINK_CHECK_RATE_LIMIT", "namespace_id": "1001", "simple": { "limit": 5, "period": 60 } }]
}

The main field points to the generated server entry, while KV namespaces and rate limits are configured but sandboxed during local development.

File-Based Routing

Routes are defined using createFileRoute from @tanstack/react-router. For example, in [web/src/routes/_marketing/index.tsx](https://github.com/every-app/open-seo/blob/main/web/src/routes/_marketing/index.tsx):

import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/_marketing")({
  component: () => <MarketingHome />,
});

TanStack Router automatically generates the route tree (see routeTree.gen.ts), providing type-safe parameters and client-side navigation without boilerplate.

Server Functions

Secure server-side logic uses createServerFn. In [web/src/lib/content.functions.ts](https://github.com/every-app/open-seo/blob/main/web/src/lib/content.functions.ts), functions fetch DataForSEO data while keeping API keys server-side:

import { createServerFn } from "@tanstack/react-start";

export const fetchKeywordMetrics = createServerFn(
  "fetchKeywordMetrics",
  async (keyword: string) => {
    const resp = await fetch(`https://api.dataforseo.com/v3/keyword_metrics?kw=${keyword}`, {
      headers: { Authorization: `Basic ${process.env.DATAFORSEO_API_KEY}` },
    });
    return resp.json();
  },
);

These functions are called from client components but execute on the worker runtime, protecting sensitive credentials.

Debugging and Logs

When using pnpm dev:agents, logs stream to .logs/dev-server.log. This file captures Cloudflare Worker startup errors and runtime output, useful for troubleshooting or providing context to AI coding agents.

Rotate the log file manually if it grows large:

mv .logs/dev-server.log .logs/dev-server-$(date +%s).log

Summary

Frequently Asked Questions

What are the minimum Node.js requirements for OpenSEO?

OpenSEO requires Node.js 20 or higher. While the project runs on Node 20+, using Node 24+ provides native Corepack support, simplifying pnpm version management through the corepack enable command.

How do I obtain DataForSEO API credentials?

You must create an account at DataForSEO and generate API keys from their dashboard. The credentials require Base64 encoding (login:password format) and must be stored in the DATAFORSEO_API_KEY environment variable in your .env.local file.

What is the difference between pnpm dev and pnpm dev:agents?

pnpm dev starts the standard Vite development server on port 4322. pnpm dev:agents (recommended) starts the server through portless, which provides stable logging to .logs/dev-server.log and supports automatic subdomain routing for git worktrees (e.g., feature-branch.open-seo.localhost:1355).

Can I use PostgreSQL instead of SQLite for local development?

Yes, while SQLite D1 is the default (pnpm run db:migrate:local), OpenSEO supports PostgreSQL as an opt-in alternative. Configuration details are documented in [docs/LOCAL_POSTGRES.md](https://github.com/every-app/open-seo/blob/main/docs/LOCAL_POSTGRES.md), including connection string setup and migration commands.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →