mirror of
https://github.com/vercel/workflow.git
synced 2026-09-14 19:59:43 +08:00
bb910f2571
* [workbench] Add TanStack Start workbench and tests (#1875) (cherry picked from commit8202663857) * Fix pnpm type issue after tanstack PR (#1907) (cherry picked from commita7071bf3d4)
242 lines
6.6 KiB
Plaintext
242 lines
6.6 KiB
Plaintext
---
|
|
title: TanStack Start
|
|
description: Set up your first durable workflow in a TanStack Start application.
|
|
type: guide
|
|
summary: Set up Workflow SDK in a TanStack Start app.
|
|
prerequisites:
|
|
- /docs/getting-started
|
|
related:
|
|
- /docs/foundations/workflows-and-steps
|
|
---
|
|
|
|
This guide will walk through setting up your first workflow in a TanStack Start app. Along the way, you'll learn more about the concepts that are fundamental to using the Workflow SDK in your own projects.
|
|
|
|
---
|
|
|
|
<Steps>
|
|
|
|
<Step>
|
|
## Create Your TanStack Start Project
|
|
|
|
Start by creating a new TanStack Start project:
|
|
|
|
```bash
|
|
npm create @tanstack/start@latest my-workflow-app
|
|
```
|
|
|
|
Enter the newly made directory:
|
|
|
|
```bash
|
|
cd my-workflow-app
|
|
```
|
|
|
|
### Install `workflow`
|
|
|
|
```package-install
|
|
npm i workflow
|
|
```
|
|
|
|
### Configure TanStack Start
|
|
|
|
TanStack Start runs on Vite, so the Workflow SDK is wired in via the same `workflow/vite` plugin. Add `workflow()` to your Vite config to enable usage of the `"use workflow"` and `"use step"` directives.
|
|
|
|
```typescript title="vite.config.ts" lineNumbers
|
|
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
|
|
import { defineConfig } from "vite";
|
|
import { workflow } from "workflow/vite";
|
|
|
|
export default defineConfig({
|
|
plugins: [
|
|
workflow(), // [!code highlight]
|
|
tanstackStart(),
|
|
],
|
|
});
|
|
```
|
|
|
|
<Accordion type="single" collapsible>
|
|
<AccordionItem value="typescript-intellisense" className="[&_h3]:my-0">
|
|
<AccordionTrigger className="text-sm">
|
|
### Setup IntelliSense for TypeScript (Optional)
|
|
</AccordionTrigger>
|
|
<AccordionContent className="[&_p]:my-2">
|
|
|
|
To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json`:
|
|
|
|
```json title="tsconfig.json" lineNumbers
|
|
{
|
|
"compilerOptions": {
|
|
// ... rest of your TypeScript config
|
|
"plugins": [
|
|
{
|
|
"name": "workflow" // [!code highlight]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
</Accordion>
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
|
|
## Create Your First Workflow
|
|
|
|
Create a new file for our first workflow:
|
|
|
|
```typescript title="src/workflows/user-signup.ts" lineNumbers
|
|
import { sleep } from "workflow";
|
|
|
|
export async function handleUserSignup(email: string) {
|
|
"use workflow"; // [!code highlight]
|
|
|
|
const user = await createUser(email);
|
|
await sendWelcomeEmail(user);
|
|
|
|
await sleep("5s"); // Pause for 5s - doesn't consume any resources
|
|
await sendOnboardingEmail(user);
|
|
|
|
return { userId: user.id, status: "onboarded" };
|
|
}
|
|
```
|
|
|
|
We'll fill in those functions next, but let's take a look at this code:
|
|
|
|
* We define a **workflow** function with the directive `"use workflow"`. Think of the workflow function as the _orchestrator_ of individual **steps**.
|
|
* The Workflow SDK's `sleep` function allows us to suspend execution of the workflow without using up any resources. A sleep can be a few seconds, hours, days, or even months long.
|
|
|
|
## Create Your Workflow Steps
|
|
|
|
Let's now define those missing functions.
|
|
|
|
```typescript title="src/workflows/user-signup.ts" lineNumbers
|
|
import { FatalError } from "workflow"
|
|
|
|
// Our workflow function defined earlier
|
|
|
|
async function createUser(email: string) {
|
|
"use step"; // [!code highlight]
|
|
|
|
console.log(`Creating user with email: ${email}`);
|
|
|
|
// Full Node.js access - database calls, APIs, etc.
|
|
return { id: crypto.randomUUID(), email };
|
|
}
|
|
|
|
async function sendWelcomeEmail(user: { id: string; email: string; }) {
|
|
"use step"; // [!code highlight]
|
|
|
|
console.log(`Sending welcome email to user: ${user.id}`);
|
|
|
|
if (Math.random() < 0.3) {
|
|
// By default, steps will be retried for unhandled errors
|
|
throw new Error("Retryable!");
|
|
}
|
|
}
|
|
|
|
async function sendOnboardingEmail(user: { id: string; email: string}) {
|
|
"use step"; // [!code highlight]
|
|
|
|
if (!user.email.includes("@")) {
|
|
// To skip retrying, throw a FatalError instead
|
|
throw new FatalError("Invalid Email");
|
|
}
|
|
|
|
console.log(`Sending onboarding email to user: ${user.id}`);
|
|
}
|
|
```
|
|
|
|
Taking a look at this code:
|
|
|
|
* Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
|
|
* If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
|
|
* Steps can throw a `FatalError` if an error is intentional and should not be retried.
|
|
|
|
<Callout>
|
|
We'll dive deeper into workflows, steps, and other ways to suspend or handle events in [Foundations](/docs/foundations).
|
|
</Callout>
|
|
|
|
</Step>
|
|
|
|
<Step>
|
|
|
|
## Create Your Route Handler
|
|
|
|
To invoke your new workflow, add a server handler at `src/routes/api/signup.ts`:
|
|
|
|
```typescript title="src/routes/api/signup.ts"
|
|
import { createFileRoute } from "@tanstack/react-router";
|
|
import { json } from "@tanstack/react-start";
|
|
import { start } from "workflow/api";
|
|
import { handleUserSignup } from "../../workflows/user-signup";
|
|
|
|
export const Route = createFileRoute("/api/signup")({
|
|
server: {
|
|
handlers: {
|
|
POST: async ({ request }) => {
|
|
const { email } = await request.json();
|
|
// Executes asynchronously and doesn't block your app
|
|
await start(handleUserSignup, [email]);
|
|
return json({ message: "User signup workflow started" });
|
|
},
|
|
},
|
|
},
|
|
});
|
|
```
|
|
|
|
This route handler creates a `POST` request endpoint at `/api/signup` that will trigger your workflow.
|
|
|
|
<Callout>
|
|
Workflows can be triggered from API routes or any server-side code.
|
|
</Callout>
|
|
|
|
</Step>
|
|
|
|
</Steps>
|
|
|
|
## Run in development
|
|
|
|
To start your development server, run the following command in your terminal in the TanStack Start root directory:
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
Once your development server is running, you can trigger your workflow by running this command in the terminal:
|
|
|
|
```bash
|
|
curl -X POST --json '{"email":"hello@example.com"}' http://localhost:3000/api/signup
|
|
```
|
|
|
|
Check the dev server logs to see your workflow execute as well as the steps that are being processed.
|
|
|
|
Additionally, you can use the [Workflow SDK CLI or Web UI](/docs/observability) to inspect your workflow runs and steps in detail.
|
|
|
|
```bash
|
|
# Open the observability Web UI
|
|
npx workflow web
|
|
# or if you prefer a terminal interface, use the CLI inspect command
|
|
npx workflow inspect runs
|
|
```
|
|
|
|

|
|
|
|
---
|
|
|
|
## Deploying to production
|
|
|
|
Workflow SDK apps currently work best when deployed to [Vercel](https://vercel.com/home) and needs no special configuration.
|
|
|
|
<FluidComputeCallout />
|
|
|
|
Check the [Deploying](/docs/deploying) section to learn how your workflows can be deployed elsewhere.
|
|
|
|
## Next Steps
|
|
|
|
* Learn more about the [Foundations](/docs/foundations).
|
|
* Check [Errors](/docs/errors) if you encounter issues.
|
|
* Explore the [API Reference](/docs/api-reference).
|