Stop writing
redundant code.

A spec-driven code generator that keeps your codebase consistent and up-to-date, so you can focus writing the code that sets your app apart.

Keep your codebase consistent

Maintaining a consistent codebase is hard. But it is the key to efficiency and scalability. Naming conventions, design patterns and coding standards are a big part of this. ZappJS ensures uniformity across your entire project.

spec.yml
models:
  post:
    attributes:
      title:
        required: true
        type: string
        unique: true
      content:
        required: true
        type: string
  user:
    attributes:
      name:
        type: string
PostsTable.ts
import { ColumnType, Generated, sql } from 'kysely'

import { db } from '@/lib/db'

export interface PostsTable {
  id: Generated<number>
  title: string
  content: string
  createdAt: ColumnType<Date, string | undefined, never>
}

export const createPostsTable = async () => {
  await db.schema
    .createTable('posts')
    .ifNotExists()
    .addColumn('id', 'serial', (cb) => cb.primaryKey())
    .addColumn('title', 'varchar(255)', (cb) => cb.notNull().unique())
    .addColumn('content', 'varchar(255)', (cb) => cb.notNull())
    .addColumn('createdAt', sql`timestamp with time zone`, (cb) =>
      cb.defaultTo(sql`current_timestamp`)
    )
    .execute()
}
UsersTable.ts
import { ColumnType, Generated, sql } from 'kysely'

import { db } from '@/lib/db'

export interface UsersTable {
  id: Generated<number>
  name?: string
  createdAt: ColumnType<Date, string | undefined, never>
}

export const createUsersTable = async () => {
  await db.schema
    .createTable('users')
    .ifNotExists()
    .addColumn('id', 'serial', (cb) => cb.primaryKey())
    .addColumn('name', 'varchar(255)')
    .addColumn('createdAt', sql`timestamp with time zone`, (cb) =>
      cb.defaultTo(sql`current_timestamp`)
    )
    .execute()
}

Breeze through migrations and upgrades

Your needs and dependencies change constantly. It's easy to fall behind and can even bring your app to a sudden hault. ZappJS enables you to effortlessly adapt your existing codebase to new standards and upgrades, minimizing manual effort and reducing the scope for errors.

Migrating from Mongoose to Prisma

spec.yml
models:
  user:
    attributes:
      name:
        type: string
      location:
      	type: string
      age:
        type: number
User.js
const mongoose = require('mongoose');

const User = mongoose.model(
  'User',
  {
    name: String,
    location: String,
    age: Number
  }
);
schema.prisma
model User {
  id       Int     @id @default(autoincrement())
  name     String
  location String
  age      Int
}

Upgrading from Class Components to Function Components

spec.yml
pages:
  home:
    render:
      - h1: Hello, world
home.jsx
import { Component } from "react";

class HomePage extends Component {
  render() {
    return <h1>Hello, world</h1>;
  }
}
home.tsx
import { FC } from "react";

const HomePage: FC = () =>
  <h1>Hello, world</h1>;

Use alongside your handwritten code

Effortlessly blend automated and manual code. Designed for synergy, ZappJS allows you to generate essential code structures automatically while providing the flexibility to write your custom code alongside.

Choose whether to generate your models, handlers, both, or neither

spec.yml
models:
  post:
    attributes:
      title:
        type: string
      content:
        type: string
post.go (generated)
package models

import "time"

type Post struct {
    ID        int       `json:"id"`
    Title     string    `json:"title"`
    Content   string    `json:"content"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}
post_handlers.go (handwritten)
package handlers

import (
    "net/http"
    "time"

    "github.com/gin-gonic/gin"
    "gorm.io/gorm"
    "my-app/models"
)

func CreatePost(db *gorm.DB) gin.HandlerFunc {
  return func(c *gin.Context) {
      var newPost models.Post
      if err := c.ShouldBindJSON(&newPost); err != nil {
          c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
          return
      }

      // write some other code

      db.Create(&newPost)
      c.JSON(http.StatusCreated, newPost)
  }
}

Spec how you want

The power to define your specifications lies in your hands. Embrace the freedom to use industry-standard specifications for familiarity and best practices, or blaze your own trail with custom specifications tailored to your unique requirements.

Use a standard like Swagger or roll with your own.

spec.yml
paths:
  /pet:
    post:
      operationId: addPet
      requestBody:
        description: Create a new pet in the store
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
        required: true
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        '405':
          description: Invalid input
spec.yml
calls:
  addPet:
    description: Create a new pet in the store
    request:
      $ref: '#/models/pet' 
    response:
      $ref: '#/models/pet'

Generate code in any language

ZappJS breaks down the barriers of language-specific limitations, offering you the freedom to generate code in the language of your choice.

Build anything

Apps, websites, APIs, desktop applications, CLI tools, games. Anything you can code manually, you can use ZappJS to generate all or part of your codebase.

Generate models for an API

spec.yml
models:
  user:
    attributes:
      name:
        type: string
      location:
      	type: string
      age:
        type: number
User.js
const mongoose = require('mongoose');

const User = mongoose.model(
  'User',
  {
    name: String,
    location: String,
    age: Number
  }
);

Generate pages for a website

spec.yml
props:
  name:
    default: world
    type: string
render:
  - h1:
      class:
        - text-bold
        - text-2xl
        - text-white
      text: Hello, {name}
home.jsx
import { FC } from "react";

interface Props {
  name?: string;
}

const Greeting: FC<Props> = ({ name = 'world' }) => {
  return (
    <h1 className="text-bold text-2xl text-white">
      Hello, {name}
    </h1>
  );
}

Generate a CLI program

spec.yml
name: string-util
description: CLI to some JavaScript string utilities
version: 0.8.0
commands:
  split:
    description: Split a string into substrings and display as an array
    arguments:
      - description: string to split
        type: string
    options:
      - flag: --first
        description: display just the first substring
      - flag: -s, --separator <char>
        description: separator character
        default: ,
home.jsx
const { Command } = require('commander');

const splitAction = require('./actions/split');

const program = new Command();

program
  .name('string-util')
  .description('CLI to some JavaScript string utilities')
  .version('0.8.0');

program.command('split')
  .description('Split a string into substrings and display as an array')
  .argument('<string>', 'string to split')
  .option('--first', 'display just the first substring')
  .option('-s, --separator <char>', 'separator character', ',')
  .action(splitAction);

program.parse();

Leave anytime

If you ever want to stop using ZappJS, just remove the `.zapp` directory and keep shipping. We will miss you and are honored to be a part of your journey.

spec.yml
models:
  post:
    attributes:
      title:
        type: string
      content:
        type: string
post.go
package models

import "time"

type Post struct {
    ID        int       `json:"id"`
    Title     string    `json:"title"`
    Content   string    `json:"content"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}
Terminal
$ rm -rf .zapp

Want to learn more?

Check out the source code and follow us on X!