Building a full-stack application involves more than creating React components and connecting them to an API. You also need to handle server-side rendering, database access, environment variables, routing, and production deployment.
TanStack Start brings these responsibilities into one framework. Built on TanStack Router and powered by Vite or Rsbuild, it supports server-side rendering (SSR), streaming, server functions, and client-side navigation.
However, a successful local build does not guarantee that an application will work correctly after deployment. Missing environment variables, incorrect server configuration, and differences between local and production runtimes can cause problems.
This article explains how to prepare a TanStack Start application for production, configure its server environment, deploy it to a hosting platform, and verify that it works as expected.
What Is TanStack Start?
TanStack Start is a full-stack React framework that combines routing, server rendering, and server-side application logic.
Unlike a client-only React application, which typically downloads JavaScript and renders the interface in the browser, a TanStack Start application can render pages on the server before sending them to the client.
Its main capabilities include:
- File-based routing with type-safe navigation.
- Server-side rendering and streaming.
- Route loaders for fetching data.
- Server functions for running server-side logic.
- Client-side navigation and interactive components.
- Production builds for supported hosting platforms and runtimes.
For example, a dashboard application might use a route loader to retrieve account information, render the initial page on the server, and then use client-side navigation when the user opens another section.
The framework handles much of the infrastructure, but developers remain responsible for authentication, authorization, database security, environment configuration, and deployment operations.
Step 1: Create a TanStack Start Application
Start with a new application or use an existing project that already runs locally.
For a new project, use the TanStack CLI:
npx @tanstack/cli@latest create my-tanstack-app
Follow the prompts to select the project configuration. The generated project includes the files and scripts required for development.
Move into the project directory:
cd my-tanstack-app
Install the dependencies if the CLI has not already done so:
npm install
Start the development server:
npm run dev
Open the local address displayed in the terminal. Confirm that the application loads and that navigation works before proceeding.
Understand the project structure
A typical project includes files similar to these:
my-tanstack-app/
├── src/
│ ├── routes/
│ │ ├── __root.tsx
│ │ └── index.tsx
│ ├── router.tsx
│ └── routeTree.gen.ts
├── public/
├── package.json
├── vite.config.ts
└── tsconfig.json
The exact structure depends on the selected template and configuration.
The src/routes directory contains route definitions, while the root route defines the shared application layout. The router manages navigation and route matching.
The generated route tree is generally maintained by the framework's tooling. Avoid manually editing generated files unless the project documentation explicitly requires it.
Step 2: Add Server-Side Data Access
A full-stack application often needs to retrieve information from a database or an internal service.
TanStack Start provides server functions for operations that must run on the server but can be called from application code.
Consider a simple function that returns the current server time.
import { createServerFn } from "@tanstack/react-start";
export const getServerTime = createServerFn({
method: "GET"
}).handler(async () => {
return {
time: new Date().toISOString()
};
});
This function runs on the server. TanStack Start manages the communication between the client and the server when the function is called from browser-side code.
A route can call the function through its loader:
import { createFileRoute } from "@tanstack/react-router";
import { getServerTime } from "../server/time";
export const Route = createFileRoute("/")({
loader: () => getServerTime(),
component: HomePage
});
function HomePage() {
const result = Route.useLoaderData();
return (
<main>
<h1>My Application</h1>
<p>Server time: {result.time}</p>
</main>
);
}
The file paths in this example assume the function is stored in src/server/time.ts and the route is src/routes/index.tsx. Adjust the imports to match your project.
The example demonstrates the server-function pattern without requiring a database. In a real application, the same approach can be used to retrieve records or call an internal service.
Important: A server function is not automatically safe simply because it runs on the server. Validate incoming data, check the current user's permissions, and avoid returning sensitive information to the browser.
If an endpoint must support callers outside the application, use an appropriate server route or API endpoint rather than treating a server function as a general public API.
Step 3: Configure Environment Variables
Applications commonly need database connection strings, authentication secrets, and external service credentials.
Keep these values outside the source code.
Create a local .env file:
DATABASE_URL=postgresql://app_user:local_password@localhost:5432/appdb
EXTERNAL_API_SECRET=replace_with_local_secret
VITE_APP_NAME=My TanStack App
The values above are examples for local development. Replace them with valid settings for your environment.
Use unprefixed variables for server-only secrets. Variables with a public prefix such as VITE_ can be exposed to browser code through the build process, so never use that prefix for passwords, private API keys, or database credentials.
For example, server-side code can read a database connection string:
import { createServerFn } from "@tanstack/react-start";
export const getDatabaseStatus = createServerFn({
method: "GET"
}).handler(async () => {
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) {
throw new Error("DATABASE_URL is not configured");
}
// Use databaseUrl to initialize the database client
// and perform an appropriate health check.
return {
configured: true
};
});
This example checks whether the setting exists; it does not verify that the database is reachable.
Read environment variables inside server handlers or other appropriate request-time callbacks. Some hosting environments provide runtime bindings only when a request is being processed, so reading them at module initialization can produce unexpected results.
Before deployment, configure production values in your hosting provider's environment settings. Do not commit .env files containing secrets to source control.
Step 4: Prepare the Production Build
Before deploying, verify that the application can produce a production build.
npm run build
Use the build script generated by your project template. A standard TanStack Start project using Vite commonly builds through Vite's production build process.
The resulting output contains the client assets and server-side output required by the selected deployment configuration.
Do not assume that every hosting platform expects the same output structure. A Node.js server deployment, an edge runtime, and a serverless platform may require different adapters or build settings.
Choose the hosting environment
TanStack Start supports multiple deployment targets, including Node.js, Cloudflare Workers, Netlify, Railway, and Vercel through their supported integrations.
Choose a platform based on the application's requirements rather than selecting one solely because it supports React.
Deployment option | Suitable for | Main consideration |
|---|
Node.js server | Applications requiring a conventional server runtime | You manage the server process and infrastructure |
Cloudflare Workers | Applications suited to an edge runtime | Check runtime API compatibility and environment bindings |
Vercel | Applications using its supported deployment workflow | Configure the appropriate framework integration and environment variables |
Netlify | Applications using its supported Vite integration | Confirm that the adapter and build settings match the project |
Railway | Applications that benefit from a managed application service | Configure build commands, startup commands, and secrets |
The deployment configuration should match the runtime that will execute the server code. A build that targets one environment may not work unchanged in another.
Step 5: Deploy to a Node.js Hosting Environment
A Node.js deployment is a useful starting point when the application depends on server-side packages or requires a conventional server process.
For a Vite-based TanStack Start project, the official deployment guidance supports using Nitro to produce a deployable server output.
Install Nitro:
npm install nitro
Update the Vite configuration to include the TanStack Start, Nitro, and React plugins:
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import { defineConfig } from "vite";
import { nitro } from "nitro/vite";
import viteReact from "@vitejs/plugin-react";
export default defineConfig({
plugins: [
tanstackStart(),
nitro(),
viteReact()
]
});
Use the configuration recommended for the versions installed in your project. If your existing template already configures the necessary plugins, update it carefully instead of duplicating entries.
Next, configure the build and start scripts in package.json:
{
"scripts": {
"dev": "vite dev",
"build": "vite build",
"start": "node .output/server/index.mjs"
}
}
Preserve any other scripts generated by your template. The start command shown here assumes the Nitro configuration produces the indicated server entry file. Verify the actual output path after building.
Run the production build:
npm run build
Then start the application locally in production mode:
npm run start
Check the terminal output and open the application in a browser. Confirm that server-rendered routes and client-side interactions work correctly.
When deploying, configure the hosting platform to install dependencies, run the build command, and start the server using the correct command for the generated output.
Also ensure that the server listens on the host and port expected by the hosting platform. Do not assume that every provider uses the same port or networking configuration.
Step 6: Verify the Application After Deployment
A deployment is not complete simply because the hosting platform reports success.
Test the application using its public address and verify the following areas.
Routing and server rendering
Open the home page and several nested routes directly in the browser. Refresh a nested route instead of reaching it only through client-side navigation.
This helps identify problems with route handling, server rendering, and fallback configuration.
Server functions
Trigger operations that use server functions. Confirm that they return the expected data and that errors are handled correctly.
Check that server-side exceptions do not expose credentials, internal file paths, or sensitive database details to users.
Environment variables
Verify that the application can connect to its required services using production configuration.
Test the failure path as well. If a required variable is missing, the application should fail clearly and produce useful server-side diagnostics without exposing secret values.
Database and external services
Confirm that database connections, authentication providers, and external APIs work from the deployed environment.
Check network access rules, database permissions, connection limits, and timeout settings.
Logging and monitoring
Review server logs after deployment. Configure appropriate monitoring for errors, latency, and service availability.
Avoid logging passwords, access tokens, session cookies, or unnecessary personal data.
Common Deployment Problems and Troubleshooting
Problem | Possible cause | What to check |
|---|
The production build fails | Missing dependency or incompatible configuration | Review the build output and installed package versions |
The application starts locally but fails on the host | Incorrect start command or output path | Check the generated server entry and hosting configuration |
A nested route returns a 404 | Server routing or deployment configuration is incorrect | Test direct navigation and review the hosting integration |
Database access fails in production | Missing secret, network restriction, or invalid credentials | Verify environment settings and database connectivity |
Server functions return errors | Validation failure, server exception, or request configuration issue | Review server logs and request handling |
A secret is visible in browser assets | A sensitive variable was exposed to client code | Remove public prefixes from secrets and move sensitive operations to server-only code |
The application works in development but not production | Runtime differences or missing production configuration | Test the production build locally and compare environment settings |
When diagnosing an issue, identify whether it originates in the build process, server runtime, browser, or external service. This prevents unrelated configuration changes from hiding the actual cause.
Best Practices for Production Deployment
- Keep secrets on the server. Store credentials in the hosting provider's secret management or environment configuration. Never include them in client-side code.
- Validate incoming data. Server functions cross a network boundary. Validate request values and enforce authorization before reading or modifying protected records.
- Use a production-like test environment. Test the production build with realistic environment settings before releasing it to users.
- Pin and review dependencies. Use a lockfile and review framework, adapter, and runtime upgrades before deploying them.
- Configure health checks and monitoring. Monitor server errors, response times, and dependencies that can affect availability.
- Plan for database failures. Apply appropriate timeouts, connection management, and error handling. Do not assume that a successful application startup means the database will always be available.
- Protect server functions. Follow the framework's security guidance for request validation and cross-site request protection. Public APIs may require different routing and authentication rules.
- Keep deployment configuration version-controlled. Store non-secret configuration and deployment files in source control so changes can be reviewed and reproduced.
Advantages and Disadvantages of TanStack Start
Advantages
- Combines routing, server rendering, and server-side functions in one framework.
- Supports type-safe navigation and data loading.
- Provides flexible deployment options for supported runtimes.
- Allows server-side operations without requiring every feature to use a separate API service.
- Supports client-side navigation alongside server-rendered pages.
Disadvantages
- Requires understanding both browser-side and server-side execution.
- Deployment configuration varies by hosting provider and runtime.
- Server functions still require validation, authorization, and security controls.
- Production debugging can involve the framework, hosting platform, and external services.
- Framework and adapter upgrades may require configuration changes.
Summary
TanStack Start provides the tools needed to build and deploy full-stack React applications with server-side rendering, type-safe routing, and server functions. A reliable deployment still depends on choosing the correct runtime, configuring environment variables securely, and testing the production build.
Start by creating or preparing the application, implementing server-side data access, and separating public configuration from secrets. Then select a supported hosting target, configure its build and startup commands, and verify routing, server functions, database connectivity, and monitoring after deployment.
The most important step is to test the application in an environment that closely matches production. A successful build is only one part of deployment; the application must also handle real requests, protect sensitive data, and recover from operational failures.
Join the conversation! Your thoughts help the community grow.