---
title: Create and Approve a Blueprint
sidebarTitle: Create and approve a blueprint
description: Author a fleet-wide compose template, target it at a node with a label, and walk through the confirm-before-mutate rollout that puts it on the fleet.
---
Every other lane in Sencho manages one Compose file on one node. A **Blueprint** is the other lane: you declare a Compose file once, point it at the nodes you want by label or by ID, and Sencho keeps those nodes in sync with that declaration going forward, deploying it where it's missing and telling you the moment a targeted node drifts from what you declared. This walks through the two-part motion every Blueprint goes through before it touches your fleet: you **create** it (author the compose, pick a target, choose how drift gets handled), then you **approve** it (review exactly what Sencho is about to place, and confirm). By the end, a small stateless service is running on a real node, deployed entirely through the Blueprint you approved rather than a manual `docker compose up`.
This tutorial does not cover stateful Blueprints (the extra confirmation step for named volumes and bind mounts), pinning a Blueprint to a specific node, or moving a deployment between nodes. See the [Blueprints](/features/blueprint-model) feature page for stateful workflows, and [Move a Blueprint Deployment to a New Node](/tutorials/set-up-fleet-federation) once you've completed this one and want to relocate a deployment with Federation.
## Prerequisites
- **An admin account.** Creating, editing, and applying a Blueprint all require the admin role. Operators and viewers can read the catalog and the detail sheet but can't act on either.
- **At least one node**, local or remote, that you can attach a label to. Blueprints are a Community-tier capability; no paid plan is required.
Blueprints target nodes by label or by explicit node ID. Open **Settings → Infrastructure → Nodes**, find the node you want this Blueprint to reach, and click the **+** button in its **Labels** column. Type `edge` and click **Add**.
Labels are plain lowercase strings, not key/value pairs. You can add more than one to a node, and a Blueprint's selector can match on any combination of them.
Go to **Fleet → Deployments** and click **New Blueprint**. Fill in:
- **Name**: `whoami-edge`
- **Description**: `Minimal identity endpoint for the edge tier`
In the **Compose** editor, replace the placeholder YAML with a small, stateless HTTP service that just echoes back which container answered, useful for confirming a deploy actually landed:
```yaml
services:
app:
image: traefik/whoami:v1.10
restart: unless-stopped
ports:
- "8080:80"
```
As you type, the classification banner above the editor updates. With no volumes in this compose, it settles on **Stateless · portable**: Sencho can deploy and evict this Blueprint freely, with none of the extra confirmation prompts a stateful Blueprint requires.
Scroll down to **Selector** and leave **Labels** selected. Click the `edge` pill under **Match nodes with ANY of these labels**. The line below confirms `Resolves to nodes labelled any of [edge]`. Under **Drift policy**, leave **Suggest** selected, the middle option: Sencho will always detect drift on this Blueprint, and Suggest additionally sends a notification when it happens, without redeploying anything on its own. (**Observe** stays silent about drift beyond the deployment row; **Enforce** auto-redeploys to fix it.)
Click **Create blueprint**.
The detail sheet opens on your new Blueprint: `any=[edge] · suggest · rev 1`, with **Apply now**, **Edit**, **Disable**, and **Delete** across the top. The **Deployments** section is still empty, with the note `No matching nodes yet. Add a label or pick a node ID, then click Apply now.`
This is expected, not a bug: creating a Blueprint only declares intent. Sencho computes what it would actually do, and does it, only once you open the rollout preview.
Click **Apply now**. Sencho computes a rollout preview: `Safe 1 · Warnings 1 · Blockers 0`, with a warning noting `no persistent volumes detected` (informational for a stateless Blueprint, not a problem), and one line under **Changes**: `Local (local/online) · create · safe: New placement`.
This preview is the actual authorization step: nothing on the fleet has changed yet, and Sencho is showing you exactly what it's about to do before it does it. Click **Confirm Apply**.
## Verify it worked
Check from two places, since a single stale UI element could tell you the wrong thing.
**The Deployments tab.** Back on **Fleet → Deployments**, the `whoami-edge` tile now shows a green dot, the **stateless** chip, and `1/1 active · any=[edge]`. Open the tile: the deployment table lists **Local**, status **Active**, with a **Withdraw** action now available. The stack also appears in the left sidebar's stack list like any other running stack, materialized on disk the same way a per-stack deploy would be.
**The audit log.** Open **Audit**, switch to **Table**, and search `blueprints/1` (or whatever ID your Blueprint got, visible in the browser's address bar or in the raw preview response). You'll see a `POST /api/blueprints/1/apply` row for each time you clicked **Confirm Apply**, each logged with your account, a timestamp, and a 200 status. If you also hit and fixed a port conflict (see below), a `PUT /api/blueprints/1` row from saving the edit shows up between the two applies.
## If something goes wrong
The most common first-time failure is a host port that's already taken. `8080` is a common default that other containers on the same node may already be bound to. If that happens, the deployment row moves to **Failed**, and the notes column carries the real Docker error, ending in something like `Bind for 0.0.0.0:8080 failed: port is already allocated`.
To recover, click **Edit**, change the host-side port in the `ports` mapping to something free (`8091:80`, for instance), and **Save changes**. Saving bumps the revision and clears approval back to pending, so click **Apply now** again: the preview this time shows an `update` action instead of `create`. Confirm it, and the deployment moves through **Deploying** to **Active** on the new port.
## Related
The full mental model: markers, drift modes, stateful safety rails, and the reconciler's approval mechanics.
Once a Blueprint is running, use Federation's pin and cordon controls to relocate it to a different node.