Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d05914f
refactor: migrate to latest nitro v3
pi0 Nov 10, 2025
28cedf7
update workaround
pi0 Nov 10, 2025
47c62ab
fix(nitro): nitro builder using deprecated srcDir
adriandlam Nov 16, 2025
83e1fb7
fix: add back nitro config
adriandlam Nov 16, 2025
1d33230
fix: testing matrix dirs
adriandlam Nov 17, 2025
acf139d
fix(hono): externalize nitro workflow output dir
adriandlam Nov 17, 2025
3039ed2
chore: format
adriandlam Nov 17, 2025
74ad22f
fix(nitro): externalize .nitro/workflow folder
adriandlam Nov 17, 2025
969efe0
docs(hono): update getting started
adriandlam Nov 17, 2025
867bf7a
update docs and workbench
pi0 Nov 17, 2025
bdd9069
improve plugin patch
pi0 Nov 17, 2025
1d9445d
test: fix hono dev config
adriandlam Nov 17, 2025
86d043f
fix: wrong api file path in hono dev config
adriandlam Nov 17, 2025
1ea3948
fix(nitro): check all dirs for builder
adriandlam Nov 17, 2025
239a882
chore: add comments
adriandlam Nov 17, 2025
118ff69
refactor: migrate to latest nitro v3
pi0 Nov 10, 2025
923cd3c
docs: update home page frameworks
adriandlam Nov 9, 2025
8fb1895
update getting started stuff and add vite page
adriandlam Nov 9, 2025
f0f6bd7
docs: update vite getting started page
adriandlam Nov 9, 2025
727ea5b
Update docs/app/(home)/components/frameworks.tsx
adriandlam Nov 9, 2025
20cad96
Update docs/content/docs/getting-started/index.mdx
adriandlam Nov 9, 2025
c8b32ea
Apply suggestion from @adriandlam
adriandlam Nov 10, 2025
ae498e3
Update docs/app/(home)/components/frameworks.tsx
adriandlam Nov 13, 2025
9c88781
lockfile
adriandlam Nov 13, 2025
cc2201d
lockfile
adriandlam Nov 17, 2025
d7e0a72
docs: update vite getting started guide
adriandlam Nov 17, 2025
3aac4c1
format
adriandlam Nov 17, 2025
0e1cbc1
format
adriandlam Nov 18, 2025
8eda690
format
adriandlam Nov 18, 2025
dc22639
reset packages/nitro/src/index.ts
adriandlam Nov 18, 2025
40d814e
docs: fix vite getting started
adriandlam Nov 18, 2025
5ef5295
docs: fix vite getting started api route
adriandlam Nov 18, 2025
415c5bb
revert
adriandlam Nov 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 188 additions & 5 deletions docs/app/(home)/components/frameworks.tsx

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion docs/content/docs/getting-started/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Getting Started
---

import { Next, Nitro, SvelteKit, Nuxt, Hono, Bun } from '@/app/(home)/components/frameworks';
import { Next, Nitro, SvelteKit, Nuxt, Hono, Bun, AstroDark, AstroLight, TanStack, Vite } from '@/app/(home)/components/frameworks';

# Getting Started

Expand All @@ -13,6 +13,10 @@ Start by choosing your framework. Each guide will walk you through the steps to
<Next className="size-16" />
<span className="font-medium">Next.js</span>
</Card>
<Card href="/docs/getting-started/vite" className="flex flex-col items-center justify-center text-center gap-2">
<Vite className="size-16" />
<span className="font-medium">Vite</span>
</Card>
<Card href="/docs/getting-started/hono" className="flex flex-col items-center justify-center text-center gap-2">
<Hono className="size-16" />
<span className="font-medium">Hono</span>
Expand All @@ -29,4 +33,15 @@ Start by choosing your framework. Each guide will walk you through the steps to
<Nuxt className="size-16" />
<span className="font-medium">Nuxt</span>
</Card>
<Card href="/docs/getting-started/astro" disabled className="flex flex-col items-center justify-center text-center gap-2">
<AstroLight className="size-16 dark:hidden" />
<AstroDark className="size-16 hidden dark:block" />
<span className="font-medium">Astro</span>
<Badge variant="secondary">Coming soon</Badge>
</Card>
<Card href="/docs/getting-started/tanstack" disabled className="flex flex-col items-center justify-center text-center gap-2">
<TanStack className="size-16 invert" />
<span className="font-medium">TanStack Start</span>
<Badge variant="secondary">Coming soon</Badge>
</Card>
</Cards>
2 changes: 1 addition & 1 deletion docs/content/docs/getting-started/meta.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"title": "Getting Started",
"pages": ["next", "..."],
"pages": ["next", "vite", "..."],
"defaultOpen": true
}
246 changes: 246 additions & 0 deletions docs/content/docs/getting-started/vite.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
---
title: Vite
---

# Vite

This guide will walk through setting up your first workflow in a Vite app. Along the way, you'll learn more about the concepts that are fundamental to using the development kit in your own projects.

---

<Steps>

<Step>
## Create Your Vite Project

Start by creating a new Vite project. This command will create a new directory named `my-workflow-app` with a minimal setup and setup a Vite project inside it.

```bash
npm create vite@latest my-workflow-app -- --template react-ts
```

Enter the newly made directory:

```bash
cd my-workflow-app
```

### Install `workflow` and `nitro`

<Tabs items={['npm', 'pnpm', 'yarn']}>
<Tab value="npm">
<CodeBlock>
npm i workflow nitro
</CodeBlock>
</Tab>
<Tab value="pnpm">
<CodeBlock>
pnpm i workflow nitro
</CodeBlock>
</Tab>
<Tab value="yarn">
<CodeBlock>
yarn add workflow nitro
</CodeBlock>
</Tab>
</Tabs>

<Callout>
While Vite provides the build tooling and development server, Nitro adds the server framework needed for API routes and deployment. Together they enable building full-stack applications with workflow support. Learn more about Nitro [here](https://v3.nitro.build).
</Callout>

### Configure Vite

Add `workflow()` to your Vite config. This enables usage of the `"use workflow"` and `"use step"` directives.

```typescript title="vite.config.ts" lineNumbers
import { nitro } from 'nitro/vite';
import { defineConfig } from 'vite';
import { workflow } from 'workflow/vite';

export default defineConfig({
plugins: [nitro(), workflow()], // [!code highlight]
nitro: { // [!code highlight]
serverDir: './', // [!code highlight]
}, // [!code highlight]
});
```

<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="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 DevKit'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="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, we'll have to add your workflow to a `POST` API route handler, `api/signup.post.ts` with the following code:

```typescript title="api/signup.post.ts"
import { start } from 'workflow/api';
import { defineEventHandler } from 'nitro/h3';
import { handleUserSignup } from "../workflows/user-signup";

export default defineEventHandler(async ({ req }) => {
const { email } = await req.json() as { email: string };
// Executes asynchronously and doesn't block your app
await start(handleUserSignup, [email]);
return {
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 Vite 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:5173/api/signup
```

Check the Vite development server logs to see your workflow execute as well as the steps that are being processed.

Additionally, you can use the [Workflow DevKit CLI or Web UI](/docs/observability) to inspect your workflow runs and steps in detail.

```bash
npx workflow inspect runs
# or add '--web' for an interactive Web based UI
```

<img src="/o11y-ui.png" alt="Workflow DevKit Web UI" />

---

## Deploying to production

Workflow DevKit apps currently work best when deployed to [Vercel](https://vercel.com/home) and needs no special configuration.

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).
6 changes: 3 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading