Skip to main content
Deno 2 is finally here šŸŽ‰ļø
Learn more

Cav

Cav is a freelancerā€™s web framework, made for Deno. It touts a craft-brewed development flow, combining many powerful features of TypeScript and Deno to help solo devs do more with less. Guiding principles:

  • Full stack
  • Modular, maintainable server definitions
  • Isomorphic client integration
  • Automatic end-to-end typesafety
  • Use The Platform

Status: New, active, almost fully tested, and not yet ready for production.

Goals

  • Learn as much as possible about backend web frameworks, by writing one from scratch Deno
    • Zero third-party dependencies
  • It should come with everything a solo developer would need to build a modern web app (minus the database)
    • Routing
    • Static asset serving
    • (Signed) cookies and JWTs
    • Web sockets
    • Form and JSON parsing / validation
    • De/serialization of most data types, including Files, Dates, Maps, etc.
    • Dev-time bundling for TypeScript assets
    • Works with frontend frameworks like Preact
  • ā€œHello worldā€ should be as easy as deno running a tiny main.ts
    • Zero config
    • Zero CLI commands
  • The client should use types imported from the server to catch API mistakes at the IDE level automatically
    • End-to-end typesafety
    • Compatible with Zod data parsers
  • Most tasks should be typesafe without needing to write TypeScript
    • Uses inferencing and generics behind-the-scenes
    • Maximal TypeScript benefits, minimal TypeScript
  • Its syntax should be functional and declarative
    • Immutable, schema-like Router and Endpoint definitions
    • No hidden context
    • No middleware
    • No magic Yes magic šŸ§™ā€ā™‚ļø
  • Production deployments should be a simple git-commit-push

Non-goals

  • React-first
  • Built-in SSR and hydration
  • SSG
  • Strict file/folder structure
  • File-system based routing
  • Make everyone happy
  • Money

Inspirations

Notes

Links and thoughts related to Cavā€™s architecture.

  • HackerNews: TRPC: End-to-end typesafe APIs made easy (trpc.io)
    • Cav and tRPC scratch a similar itch, but Cav wanders a little further into Express territory.

      When I started writing what would become Cav, tRPC couldnā€™t (on its own) accept posted bodies that werenā€™t JSON, which led to a craving for an input normalization step before the parsing step that could accept both JSON and regular HTML forms. i.e. an endpoint with a single input parser could use it to parse both FormData and JSON request bodies. This would be useful in simple static sites that only need a contact or subscription form, for example.

      I was also toying around with Denoā€™s bundler in my spare time, and superjson was something I was using at work. I loved the thought of a comprehensive, full-stack solution that combined these ideas into a unified module, built on this standards-compliant runtime I was rapidly falling for. It seemed like writing such a framework myself would be a fun learning project.

      Lessons so far: Web frameworks are hard, Deno is awesome, and making your own tools is a great way to learn things you never knew you never knew šŸƒ

    • End-to-end typesafety is fairly straightforward TypeScript witchcraft. Short summary: TypeScript strips type imports at build time, making it possible to import server-side type definitions into client-side code without runtime consequences. The client can then use those types to keep API inputs/outputs in-sync with what the server expects, triggering TS errors when something isnā€™t right. This works without requiring code generation, which is a limitation of the venerable gRPC. Add TypeScriptā€™s inferencing and generics to the mix, and a new world of developer tools is born.

      This is a really cool pattern to work with. A great resource to learn more is this essay written by Colin McDonnell, the creator of Zod and tRPC.

      It seems like thereā€™s some convergent evolution going on in the community regarding this pattern, and thereā€™s several projects mentioned in the HN comments on this post that work with similar concepts. TypeScript makes implementing this pretty simple, and Cav is just one personā€™s subjective take on what it can look like.

Dedication

Cav is dedicated to the bar itā€™s named after. šŸ»