DEV Community

Gary McPherson
Gary McPherson

Posted on

Introduction to Swarm: an extensible Typescript code generation framework

As developers, we all reach a point when writing repetitive boilerplate stops being a minor annoyance and starts having a real impact on our productivity. You find yourself creating the same directory structure, writing the same configuration blocks, copying and pasting similar component patterns, then tweaking each instance slightly. What begins as a few minutes here and there quickly adds up to hours lost on manual scaffolding.

That's where this journey began for me. Initially, I built a collection of scripts to automate component creation for a side project. But the more I used those scripts, the more I realised this problem wasn't unique to my project or the framework I was using.

Today, Swarm is an extensible TypeScript code generation framework built on a plugin-based architecture. The first plugin I created solved my own needs for generating Wasp components, but the core library can be extended to generate code for any framework or platform.

So, dear developer, I'd like to share why Swarm exists, how it came to be and what it might offer you.

Why Wasp?

Before diving into Swarm itself, it's worth sharing the context that led to its creation. While researching framework options for a side project, I discovered Wasp, a full-stack web development framework, through their OpenSaaS starter template. I'd been looking at various paid SaaS starter templates at the time, but Wasp's offering stood out because it was free and included genuinely useful features out of the box.

I've been working with Wasp for almost a year now and in that time, I've become a contributor to the project and been fortunate enough to been recognised as a community expert. I believe the team behind it has built something with genuine potential. But as a relatively early (pre-1.0) project, I encountered certain friction points as I started using it more extensively.

The Challenges

Wasp gives developers considerable freedom in how they organise their projects. That flexibility can feel empowering, but it also imposes cognitive load as you have to decide on a structure yourself, often without clear guidance on what scales well. In my first project, I implemented a feature-based structure that segregated front- and back-end components into cohesive feature directories. Conceptually, I still stand by that decision, but there are definitely implementation details I'd approach differently now.

The configuration file presents another issue. Wasp uses a single configuration file, defined in their own DSL or TypeScript, to declare all server-side components. That includes RPC-style queries, actions (mutations), CRUD operations, background jobs, HTTP API endpoints, and page routes. The file offers a shallow learning curve and it's initially easy to manage, but it's monolithic and defines every component for the application. For complex app, it can grow very large and becomes increasingly difficult to navigate, even with careful organisation.

Then there's the server-side code structure. Wasp tends to recommend organising server operations in monolithic files like actions.ts or queries.ts. This works fine for small project, but as applications grow, these files can become unwieldy. More fundamentally, this pattern contrasts sharply with typical front-end conventions that define one component per file. That inconsistency creates mental overhead when switching between client and server code.

The Journey

Swarm started out as a set of simple scripts I created to automate component creation for my first Wasp project. They worked well enough and I figured other Wasp developers might find them useful, so I decided to package them as a CLI tool that could easily be installed in other projects.

The next realisation was that MCP (Model Context Protocol) support would make these tools easier to use within AI-assisted development workflows. To enable that, I needed to break the core functionality out, with separate CLI and MCP packages, which forced me to think more carefully about the overall architecture.

Once I had both CLI and MCP working, another insight followed: this problem wasn't Wasp-specific. The same pattern of generating type-safe, context-aware boilerplate could apply to any framework. So I refactored everything into a technology-agnostic core handling both CLI command and MCP tool generation, with a separate plugin defining Wasp-specific generators.

Another revelation arrived when it struck me that CLI commands and MCP tools could be generated entirely from Zod schemas. I was already using Zod in a limited capacity throughout the application, but I realised I could define the schema once and get CLI flags, MCP tool parameters and validation for free, making plugin development much simpler.

While ironing out some compatibility bugs between the Zod 4 dependency in Swarm and the Zod 3 dependency in Wasp, I learned about Standard Schema and implemented support for that spec instead, allowing plugin schemas to be built with any library of the author's choice.

State Of The Union

At the time of writing, the Swarm "ecosystem" consists of three main components:

Swarm Core

As previously mentioned, the core framework is built around a plugin-based architecture that supports user-defined generators for different types of content, e.g. APIs, components, configuration or whatever makes sense for your use case. Generators and plugins implement simple, lightweight interfaces and leverage Standard Schema schemas for input validation.

export interface Generator<S extends StandardSchemaV1 = StandardSchemaV1> {
  name: string;
  description: string;
  schema: S;
  generate: (args: Out<S>) => Promise<void>;
}

export interface Plugin {
  name: string;
  providers: Array<GeneratorProvider>;
}
Enter fullscreen mode Exit fullscreen mode

Those schemas drive both the command-line and MCP interfaces. You define a generator with a schema, and Swarm automatically exposes it as a command-line option and as an MCP tool that AI assistants can use, with no separate configuration or manual wiring required.

Swarm also includes a templating system built on Eta, with support for custom template overrides. If you need to tweak the output of a generator, you can place a modified template in a known location and the generator will use it in favour of the built-in version.

The Swarm Wasp Plugin

The Wasp plugin provides generators for all documented Wasp components. That includes API Endpoints and Namespaces, CRUD operations, Actions, Queries, Page Routes, and Background Jobs. All output is type-safe and compatible with your defined Prisma entities.

Beyond code generation, the plugin addresses those issues I mentioned earlier:

  1. It introduces an enhanced configuration system that supports feature-based feature.wasp.ts files alongside the main main.wasp.ts. This contrasts with the traditional monolithic style, creating smaller, more manageable files and ensuring feature configuration is self-contained.
  2. It provides a fluent API through an extended App class that makes configuration files more concise and readable.
  3. It enforces a consistent, feature-based directory structure with a component-per-file pattern that mirrors front-end conventions. In the spirit of Prettier, I wanted to just take away all the concerns with "how" and just be able to focus on the "what".

The Swarm Wasp Starter

The starter template demonstrates how to build Wasp applications using Swarm's code generation functionality. It provides a minimal implementation that's an ideal foundation for building custom starter templates on top of.

It includes modern tooling like Tailwind CSS 4 and shadcn/ui components, with several useful development scripts for common Wasp workflows. And of course, it includes Swarm's full MCP integration ready for AI-assisted development. If you're building a Wasp application and want to see how Swarm can accelerate your development workflow, give it a try!

What's Next?

This introduction covered the motivation, evolution, and current state of Swarm. In Part 2, I'll walk through creating a full-stack Wasp application using the Swarm toolkit. I'll show how the generators work in practice and how they can speed up development while maintaining type safety and consistency.

And if you're a Wasp developer dealing with some of the same friction points I encountered, I'd love to hear your thoughts.

Top comments (0)