OrchStep for frontend developers
Frontend work means running the same five checks CI runs — lint, types, tests, build — against the right API base URL, then shipping a preview. Here's how to make that one workflow instead of five memorized commands.
blog/frontend-dev-tasksYou push a branch, CI goes red on a lint rule, and you spend the next ten minutes reproducing it locally — because the exact command CI runs lives in a YAML file you don't read. So you run npm run lint, then tsc, then the tests, then a build, one at a time, hoping you matched the pipeline's order and flags.
Then there's the API base URL question. Did this build point at staging or production? It's an env var three layers deep in a .env file, and getting it wrong means a preview that silently talks to the wrong backend.
This post collapses that into one OrchStep workflow: a check task that runs exactly what CI runs, and a preview task that builds and ships a preview URL. Same eslint, tsc, vitest, and bundler — just ordered and named so the laptop and the pipeline run the identical thing.
The pain, concretely
- CI fails on a check you can't easily reproduce because the command lives in pipeline YAML.
- "Which API did this build hit?" is a question you answer by reading
.envfiles. - The test step flakes on a slow CI runner, and you can't tell a real failure from a timeout.
The workflow
check is the CI mirror: install, lint, types, test, build — in order. preview reuses check as its first step, then deploys the build output and reports the URL. Because preview calls check, there is one definition of "is this branch shippable."
name: web-app
defaults:
api_base: "https://api.staging.example.test"
build_dir: dist
tasks:
# `orchstep run check` — the same checks CI runs
check:
steps:
- name: install
func: shell
do: echo "installing deps for web-app"
- name: lint
func: shell
do: echo "running eslint + prettier"
- name: types
func: shell
do: echo "running tsc --noEmit"
- name: test
func: shell
do: echo "running vitest"
retry:
max_attempts: 2
interval: "1s"
backoff_rate: 2.0
- name: build
func: shell
do: echo "building against {{ vars.api_base }} into {{ vars.build_dir }}"
# `orchstep run preview`
preview:
steps:
- name: build
task: check # ship only what passed the checks
- name: deploy
func: shell
do: echo "uploading {{ vars.build_dir }} to preview host"
outputs:
url: "https://pr-42.preview.example.test"
- name: report
func: shell
do: echo "preview ready at {{ steps.deploy.url }}"The api_base is a named variable with a visible default, not a buried env var — and you override it for a one-off build with --var api_base=https://api.example.test, no .env editing. The deploy step captures the preview URL as an output, so the report step references that captured value instead of you copy-pasting it from scrollback.
Run the exact checks CI runs
orchstep run checkThis is the whole point: the command on your laptop and the command in the pipeline are the same orchstep run check. When CI goes red, you reproduce it in one line. Wiring it into your pipeline is one step — see Running in CI.
Forgot the task name? Press a key, not your memory:
orchstep menuConfirm which backend the build targets
A dry-run resolves every variable and prints the plan, so you can read which api_base the build will use before it runs:
orchstep run preview --dry-runThat turns "I think this build hits staging" into seeing it. More in Previewing with Dry Run.
What you actually gained
| Concern | Before | OrchStep |
|---|---|---|
| Reproduce a CI failure | read pipeline YAML, guess flags | orchstep run check — same as CI |
| Which API base? | grep .env files | named api_base, overridable with --var |
| Flaky test on slow runners | re-run by hand | retry: { max_attempts: 2 } |
| Preview URL | copy from logs | captured as a step output |
| Ship something untested | easy to do by accident | preview calls check first |
If your framework's CLI already does all of this in one command, use it. The moment you're chaining four tools with conditional env vars and a deploy, this is the version a teammate can read. And nothing here replaces your bundler — it just stops you from running it with the wrong URL.
Where to go next
- Quick Start — your first workflow in two minutes
- Running in CI — the same file on your laptop and your pipeline
- Variables & Outputs — defaults,
--var, and step outputs - Environments — staging vs production as a selectable target
Tired of guessing which API a build hit? Run orchstep init and put the answer in the file.
curl -fsSL https://orchstep.dev/install.sh | sh