Skip to content

SpryBuild Dart APIs Once. Deploy Anywhere.

File-routing Dart server framework with inspectable generated output, OpenAPI generation, and first-party typed clients.

Author fast

Use the filesystem as the contract

Model routes, scoped middleware, and scoped errors with normal files instead of central route registries and framework ceremony.

Deploy wide

Change targets, not route code

Use defineSpryConfig(...) to choose the runtime target and build output without rewriting handlers for each platform.

Stay in control

Generated output is visible by design

Spry emits a real app and real runtime entry files so the build pipeline stays understandable during debugging, review, and deployment.

Why teams look at Spry

  • They want file routing in Dart, but do not want the framework to become a black box.
  • They want one API project that can ship to Dart VM locally and edge or JavaScript runtimes later.
  • They want OpenAPI and typed clients generated from the real app model instead of maintained by hand.
  • They want deployment flexibility without moving to a different server abstraction every time infrastructure changes.

Build from the file tree

Spry is organized around a runtime pipeline, not around imperative route registration. The folder tree is the contract. Route files define handlers. defineHandler(...) keeps one-off behavior local to one route. _middleware.dart and _error.dart shape broader behavior by scope. spry.config.dart decides how the generated output should run.

text
.
├─ routes/
│  ├─ index.dart
│  ├─ about.get.dart
│  ├─ users/[id].dart
│  ├─ [...slug].dart
│  ├─ _middleware.dart
│  └─ _error.dart
├─ middleware/
│  └─ 01_logger.dart
├─ public/
│  └─ hello.txt
├─ hooks.dart
└─ spry.config.dart
dart
import 'package:spry/spry.dart';

Response handler(Event event) {
  return Response.json({
    'message': 'hello from spry',
    'runtime': event.context.runtime.name,
    'path': event.url.path,
  });
}
dart
import 'package:spry/config.dart';

void main() {
  defineSpryConfig(
    host: '127.0.0.1',
    port: 4000,
    target: BuildTarget.vm,
  );
}

What you keep simple

Normal Dart handlers, local composition, direct runtime control

Spry keeps the authoring model small: folders define routes, scoped files shape behavior, and runtime choice stays in config. The result is less ceremony than a traditional server stack without hiding how the app runs.

routes/ scannerScoped middlewareScoped error boundariesPublic asset servingLifecycle hooks
  • Handlers return Response values directly.
  • defineHandler(...) can wrap one route without introducing more files.
  • Middleware composes with Next instead of global mutation.
  • Params and locals live on a request-scoped Event object.
  • Targets are selected in config rather than per-route conditionals.
  • A concrete Spry(...) app with route and middleware maps.
  • A runtime-specific main.dart entrypoint.
  • Target extras such as Vercel or Cloudflare wrappers when needed.

Good fit for

  • API projects that want file routing and explicit generated output
  • teams evaluating Dart for backend work but needing deployment flexibility
  • apps that benefit from generated OpenAPI and typed clients
  • server projects that may start on Dart VM and later move to Bun, Deno, Cloudflare, or Node.js

Less ideal for

  • teams that want a large batteries-included application platform
  • projects that need ORM, auth, jobs, and admin tooling bundled into the framework
  • codebases that prefer imperative route registration over filesystem structure

Read the docs in the same order you build

  1. Start with Getting Started to get a minimal project running.
  2. Read Project Structure, File Routing, and Middleware and Errors to learn the actual authoring model.
  3. Include Client when you want a generated first-party client.
  4. Use OpenAPI when you want stronger request and response contracts, or a generated OpenAPI document.
  5. Configure Assets, Lifecycle, Request Context, and WebSockets once the basics are in place.
  6. Use Configuration, then move to Deploy Overview when you are ready to run the same code outside Dart VM.

Spry is strongest when you want boring folders, explicit output, and deployment optionality.

Start with the quick start if you want to run a real project today, or jump to deploy docs if you are evaluating runtime targets first.

Netlify Status

Released under the MIT License.