workflow
Version:
Workflow DevKit - Build durable, resilient, and observable workflows
236 lines (163 loc) • 6.59 kB
text/mdx
---
title: Nitro
description: This guide will walk through setting up your first workflow in a Nitro v3 project. Along the way, you'll learn more about the concepts that are fundamental to using the development kit in your own projects.
type: guide
summary: Set up Workflow DevKit in a Nitro app.
prerequisites:
- /docs/getting-started
related:
- /docs/foundations/workflows-and-steps
---
<Steps>
<Step>
## Create Your Nitro Project
Start by creating a new [Nitro v3](https://v3.nitro.build/) project. This command will create a new directory named `nitro-app` and setup a Nitro project inside it.
```bash
npx create-nitro-app
```
Enter the newly made directory:
```bash
cd nitro-app
```
### Install `workflow`
```package-install
npm i workflow
```
### Configure Nitro
Add `workflow/nitro` module to your `nitro.config.ts` This enables usage of the `"use workflow"` and `"use step"` directives.
```typescript title="nitro.config.ts" lineNumbers
import { defineConfig } from "nitro";
export default defineConfig({
serverDir: "./server",
modules: ["workflow/nitro"],
});
```
<Accordion type="single" collapsible>
<AccordionItem value="typescript-intellisense" className="[&_h3]:my-0">
<AccordionTrigger className="[&_p]:my-0 text-lg [&_p]:text-foreground">
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);
console.log("Workflow is complete! Run 'npx workflow web' to inspect your run")
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 create a new API route handler at `server/api/signup.post.ts` with the following code:
```typescript title="server/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>
<Step>
## Run in development
To start your development server, run the following command in your terminal in the Nitro 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 Nitro 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
# Open the observability Web UI
npx workflow web
# or if you prefer a terminal interface, use the CLI inspect command
npx workflow inspect runs
```

</Step>
</Steps>
## Deploying to production
Workflow DevKit 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).