Hono
This guide will walk through setting up your first workflow in a Hono app. Along the way, you'll learn more about the concepts that are fundamental to using the development kit in your own projects.
Create Your Hono Project
Start by creating a new Hono project. This command will create a new directory named my-workflow-app and setup a Hono project inside it.
npm create hono@latest my-workflow-app -- --template=nodejsEnter the newly made directory:
cd my-workflow-appInstall workflow and nitro
npm i workflow nitro
pnpm i workflow nitro
yarn add workflow nitro
By default, Hono doesn't include a build system. Nitro adds one which enables compiling workflows, runs, and deploys for development and production. Learn more about Nitro here.
Configure Nitro
Create a new file nitro.config.ts for your Nitro configuration with module workflow/nitro. This enables usage of the "use workflow" and "use step" directives.
import { defineNitroConfig } from "nitro/config"; export default defineNitroConfig({ srcDir: "src", serverEntry: "index.ts", modules: ["workflow/nitro"], });Update package.json
To use the Nitro builder, update your package.json to include the following scripts:
{ // ... "scripts": { "dev": "nitro dev", "build": "nitro build" }, // ... }Create Your First Workflow
Create a new file for our first workflow:
import { sleep } from "workflow"; export async function handleUserSignup(email: string) { "use workflow"; 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
sleepfunction 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.
import { FatalError } from "workflow"; // Our workflow function defined earlier async function createUser(email: string) { "use step"; 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"; 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"; 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
FatalErrorif an error is intentional and should not be retried.
We'll dive deeper into workflows, steps, and other ways to suspend or handle events in Foundations.
Create Your Route Handler
To invoke your new workflow, we'll create a new API route handler at src/index.ts with the following code:
import { Hono } from "hono"; import { start } from "workflow/api"; import { handleUserSignup } from "../workflows/user-signup.js"; const app = new Hono(); app.post("/api/signup", async (c) => { const { email } = await c.req.json(); await start(handleUserSignup, [email]); return c.json({ message: "User signup workflow started" }); }); export default app;This route handler creates a POST request endpoint at /api/signup that will trigger your workflow.
Run in development
To start your development server, run the following command in your terminal in the Hono root directory:
npm run devOnce your development server is running, you can trigger your workflow by running this command in the terminal:
curl -X POST --json '{"email":"hello@example.com"}' http://localhost:3000/api/signupCheck the Hono 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 to inspect your workflow runs and steps in detail.
npx workflow inspect runs # add '--web' for an interactive Web based UI
Deploying to production
Workflow DevKit apps currently work best when deployed to Vercel and needs no special configuration.
Check the Deploying section to learn how your workflows can be deployed elsewhere.
Next Steps
- Learn more about the Foundations.
- Check Errors if you encounter issues.
- Explore the API Reference.