🚀 Getting Started
Want a ready‑to‑run template? Start with a starter: /from-examples
Prefer to understand how Axolotl works under the hood? Read on.
Installation
Install dependencies and the Yoga adapter:
npm i @aexol/axolotl-core @aexol/axolotl-graphql-yoga graphql-yoga graphqlCreate a schema.graphql file (or point to a URL). Axolotl will generate
type‑safe models from your schema.
Take a look at the following schema
type Beer implements Node{
	name: String!
	price: Int!
	_id: String!
}
 
type Query{
	beers: [Beer!]
	testAuth: String! @auth
}
 
type Mutation{
	addBeer(
		beer: CreateBeer!
	): String
	deleteBeer(
		_id: String!
	): Boolean
	updateBeer(
		beer: UpdateBeer!
		_id: String!
	): Boolean
}
 
input CreateBeer{
	name: String!
	price: Int!
}
 
interface Node{
	_id: String!
	createdAt: String!
}
 
input UpdateBeer{
	name: String
	price: Int
}
 
schema{
    query: Query
    mutation: Mutation
}
directive @auth on FIELD_DEFINITIONThis simple schema will produce models.ts at the path you choose.
Generate models:
npx @aexol/axolotl buildThis generates type‑safe models for your Axolotl engine. Example output:
export interface CreateBeer {
  name: string;
  price: number;
}
export interface UpdateBeer {
  name?: string | undefined;
  price?: number | undefined;
}
 
export type Models = {
  ['Beer']: {
    name: {
      args: Record<string, never>;
    };
    price: {
      args: Record<string, never>;
    };
    _id: {
      args: Record<string, never>;
    };
  };
  ['Query']: {
    beers: {
      args: Record<string, never>;
    };
    testAuth: {
      args: Record<string, never>;
    };
  };
  ['Mutation']: {
    addBeer: {
      args: {
        beer: CreateBeer;
      };
    };
    deleteBeer: {
      args: {
        _id: string;
      };
    };
    updateBeer: {
      args: {
        beer: UpdateBeer;
        _id: string;
      };
    };
  };
};
 
export type Directives = {
    auth: {
      args: Record<string, never>;
    };
};
 
export interface Beer {
  name: string;
  price: number;
  _id: string;
}
export interface Query {
  beers?: Array<Beer> | undefined;
  testAuth: string;
}
export interface Mutation {
  addBeer?: string | undefined;
  deleteBeer?: boolean | undefined;
  updateBeer?: boolean | undefined;
}Models and Directives types will be consumed by Axolotl engine. Below there
types that you can use to check if the response is valid using TypeScript
satisfies keyword.
Then create the axolotl.ts adapter entry:
import { Directives, Models } from '@/src/models.js';
import { Axolotl } from '@aexol/axolotl-core';
import { graphqlYogaAdapter } from '@aexol/axolotl-graphql-yoga';
 
export const { applyMiddleware, createResolvers, createDirectives, adapter } = Axolotl(graphqlYogaAdapter)<
  Models,
  Directives
>();Now implement resolvers in resolvers.ts:
import { createResolvers } from '@/src/axolotl.js';
import { Beer } from '@/src/models.js';
 
const Beers: Beer[] = [
  {
    _id: '0',
    createdAt: '2023-10-10T15:21:43.038Z',
    name: 'Kumple',
    price: 10,
    info: 'Dobre piwko',
  },
  {
    _id: '1',
    createdAt: '2023-10-11T14:51:09.029Z',
    name: 'Zubr',
    price: 100,
  },
];
 
export default createResolvers({
  Query: {
    beers: () => Beers,
    testAuth: () => 'TOP SECRET',
  },
  Mutation: {
    addBeer: (input, args) => {
      return Beers.push({ ...args.beer, _id: Beers.length + 1 + '', createdAt: new Date().toISOString() });
    },
    deleteBeer: (input, args) => {
      return Beers.splice(Beers.findIndex((b) => b._id === args._id));
    },
    updateBeer: (input, args) => {
      const oldElement = Beers.find((b) => b._id);
      if (!oldElement) return false;
      return Beers.splice(
        Beers.findIndex((b) => b._id === args._id),
        1,
        {
          ...oldElement,
          ...args.beer,
        },
      );
    },
  },
});Here you can have every type safe resolver implementation.
Now we need to run the resolvers using prepared adapter. Write your index.ts file.
import { adapter } from '@/src/axolotl.js';
import resolvers from '@/src/resolvers.js';
 
adapter({ resolvers }).server.listen(parseInt(process.env.PORT || '4000'), () => {
  console.log('LISTENING to ' + process.env.PORT || '4000');
});Now if we build it and run the index.js using node command - we have the
running server.
Your file tree should look like this:
- axolotl.ts
 - index.ts
 - models.ts
 - resolvers.ts