or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

browser-apis.mdcomponents-hooks.mdconfiguration.mdgraphql.mdindex.mdnode-apis.mdssr-apis.md
tile.json

node-apis.mddocs/

Node.js APIs

Server-side APIs for plugin development, page creation, data sourcing, and build-time customization through the gatsby-node.js file.

Capabilities

GatsbyNode Interface

Main interface for build-time plugin APIs that control data sourcing, page creation, schema customization, and build configuration.

/**
 * Main interface for gatsby-node.js plugin APIs
 */
interface GatsbyNode {
  /** Plugin initialization */
  onPluginInit?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** Before Gatsby initialization */
  onPreInit?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** Before bootstrap phase */
  onPreBootstrap?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** After bootstrap phase */
  onPostBootstrap?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** Before build phase */
  onPreBuild?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** After build phase */
  onPostBuild?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** Before query extraction */
  onPreExtractQueries?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** Create pages programmatically */
  createPages?: (args: CreatePagesArgs) => Promise<void> | void;
  /** Create pages with state management */
  createPagesStatefully?: (args: CreatePagesArgs) => Promise<void> | void;
  /** Modify created pages */
  onCreatePage?: (args: CreatePageArgs) => Promise<void> | void;
  /** Source nodes from external systems */
  sourceNodes?: (args: SourceNodesArgs) => Promise<void> | void;
  /** Process created nodes */
  onCreateNode?: (args: CreateNodeArgs) => Promise<void> | void;
  /** Filter node processing */
  shouldOnCreateNode?: (args: {
    node: Node;
  }, pluginOptions?: PluginOptions) => boolean;
  /** Customize GraphQL schema */
  createSchemaCustomization?: (args: CreateSchemaCustomizationArgs) => Promise<void> | void;
  /** Add GraphQL resolvers */
  createResolvers?: (args: CreateResolversArgs) => Promise<void> | void;
  /** Add fields to GraphQL node types */
  setFieldsOnGraphQLNodeType?: (args: SetFieldsOnGraphQLNodeTypeArgs) => object | Promise<object>;
  /** Modify Babel configuration */
  onCreateBabelConfig?: (args: CreateBabelConfigArgs) => Promise<void> | void;
  /** Modify Webpack configuration */
  onCreateWebpackConfig?: (args: CreateWebpackConfigArgs) => Promise<void> | void;
  /** Configure development server */
  onCreateDevServer?: (args: CreateDevServerArgs) => Promise<void> | void;
  /** Preprocess source files */
  preprocessSource?: (args: PreprocessSourceArgs) => Promise<string> | string;
  /** Add resolvable file extensions */
  resolvableExtensions?: (args: ParentSpanPluginArgs) => string[] | Promise<string[]>;
  /** Plugin options validation schema */
  pluginOptionsSchema?: (args: PluginOptionsSchemaArgs) => object;
}

Page Creation APIs

Create and manage pages programmatically during the build process.

/**
 * Create pages programmatically
 */
interface CreatePagesArgs extends ParentSpanPluginArgs {
  graphql: GraphQLFunction;
  actions: Actions;
  reporter: Reporter;
}

/**
 * GraphQL function for querying data during page creation
 */
type GraphQLFunction = <TData = any>(
  query: string,
  variables?: Record<string, any>
) => Promise<{
  errors?: any;
  data?: TData;
}>;

Usage Examples:

// gatsby-node.js
const path = require("path");

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions;

  // Query for blog posts
  const result = await graphql(`
    {
      allMarkdownRemark {
        edges {
          node {
            id
            frontmatter {
              slug
              title
            }
            html
          }
        }
      }
    }
  `);

  if (result.errors) {
    reporter.panicOnBuild("Error loading blog posts", result.errors);
    return;
  }

  // Create blog post pages
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: `/blog/${node.frontmatter.slug}`,
      component: path.resolve("./src/templates/blog-post.js"),
      context: {
        id: node.id,
        slug: node.frontmatter.slug,
      },
    });
  });

  // Create paginated blog index
  const posts = result.data.allMarkdownRemark.edges;
  const postsPerPage = 6;
  const numPages = Math.ceil(posts.length / postsPerPage);

  Array.from({ length: numPages }).forEach((_, i) => {
    createPage({
      path: i === 0 ? `/blog` : `/blog/${i + 1}`,
      component: path.resolve("./src/templates/blog-list.js"),
      context: {
        limit: postsPerPage,
        skip: i * postsPerPage,
        numPages,
        currentPage: i + 1,
      },
    });
  });
};

Data Sourcing APIs

Source and process data from external systems and files.

/**
 * Source nodes from external systems
 */
interface SourceNodesArgs extends ParentSpanPluginArgs {
  actions: Actions;
  createNodeId: CreateNodeIdFunction;
  createContentDigest: CreateContentDigestFunction;
  reporter: Reporter;
  getCache: GetCacheFunction;
  getNode: GetNodeFunction;
  getNodes: GetNodesFunction;
  hasNodeChanged: HasNodeChangedFunction;
  webhookBody?: object;
}

/**
 * Process created nodes
 */
interface CreateNodeArgs extends ParentSpanPluginArgs {
  node: Node;
  actions: Actions;
  createNodeId: CreateNodeIdFunction;
  createContentDigest: CreateContentDigestFunction;
  getNode: GetNodeFunction;
  getNodes: GetNodesFunction;
  reporter: Reporter;
}

type CreateNodeIdFunction = (input: string) => string;
type CreateContentDigestFunction = (input: string | object) => string;

Usage Examples:

// gatsby-node.js - Custom data source
exports.sourceNodes = async ({
  actions,
  createNodeId,
  createContentDigest,
  reporter,
}) => {
  const { createNode } = actions;

  try {
    // Fetch data from API
    const response = await fetch("https://api.example.com/posts");
    const posts = await response.json();

    // Create nodes for each post
    posts.forEach((post) => {
      const nodeId = createNodeId(`Post-${post.id}`);
      const nodeContent = JSON.stringify(post);

      const node = {
        ...post,
        id: nodeId,
        parent: null,
        children: [],
        internal: {
          type: "Post",
          content: nodeContent,
          contentDigest: createContentDigest(post),
        },
      };

      createNode(node);
    });

    reporter.info(`Created ${posts.length} Post nodes`);
  } catch (error) {
    reporter.panicOnBuild("Error sourcing posts from API", error);
  }
};

// Transform nodes after creation
exports.onCreateNode = ({ node, actions, createNodeId, createContentDigest }) => {
  const { createNode, createParentChildLink } = actions;

  // Process Markdown files
  if (node.internal.type === "MarkdownRemark") {
    // Extract reading time
    const readingTime = Math.ceil(node.rawMarkdownBody.split(" ").length / 200);

    // Create reading time node
    const readingTimeNode = {
      id: createNodeId(`ReadingTime-${node.id}`),
      parent: node.id,
      children: [],
      readingTime,
      text: `${readingTime} min read`,
      internal: {
        type: "ReadingTime",
        contentDigest: createContentDigest({ readingTime }),
      },
    };

    createNode(readingTimeNode);
    createParentChildLink({ parent: node, child: readingTimeNode });
  }
};

Schema Customization APIs

Define and customize the GraphQL schema for data querying.

/**
 * Customize GraphQL schema
 */
interface CreateSchemaCustomizationArgs extends ParentSpanPluginArgs {
  actions: Actions;
  schema: GatsbyGraphQLObjectType;
}

/**
 * Add GraphQL resolvers
 */
interface CreateResolversArgs extends ParentSpanPluginArgs {
  actions: Actions;
  schema: GatsbyGraphQLObjectType;
  createResolvers: CreateResolversFunction;
}

type CreateResolversFunction = (resolvers: Record<string, any>) => void;

Usage Examples:

// gatsby-node.js - Schema customization
exports.createSchemaCustomization = ({ actions, schema }) => {
  const { createTypes } = actions;

  // Define custom types
  const typeDefs = `
    type BlogPost implements Node {
      id: ID!
      title: String!
      slug: String!
      content: String!
      publishedAt: Date! @dateformat
      author: Author! @link(by: "id")
      tags: [Tag!]! @link(by: "name")
      featuredImage: File @fileByRelativePath
      readingTime: ReadingTime @link(by: "parent.id")
    }

    type Author implements Node {
      id: ID!
      name: String!
      email: String!
      bio: String
      avatar: File @fileByRelativePath
      posts: [BlogPost!]! @link(by: "author.id", from: "id")
    }

    type Tag implements Node {
      id: ID!
      name: String!
      slug: String!
      posts: [BlogPost!]! @link(by: "tags.name", from: "name")
    }
  `;

  createTypes(typeDefs);

  // Create field extension
  const slugify = (str) =>
    str
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, "-")
      .replace(/(^-|-$)+/g, "");

  createTypes(
    schema.buildObjectType({
      name: "BlogPost",
      fields: {
        slug: {
          type: "String!",
          resolve: (source) => slugify(source.title),
        },
      },
    })
  );
};

// Add custom resolvers
exports.createResolvers = ({ createResolvers }) => {
  const resolvers = {
    BlogPost: {
      relatedPosts: {
        type: ["BlogPost!"]!,
        resolve: async (source, args, context) => {
          const { entries } = await context.nodeModel.findAll({
            type: "BlogPost",
            query: {
              filter: {
                tags: { elemMatch: { name: { in: source.tags.map(t => t.name) } } },
                id: { ne: source.id },
              },
              limit: 3,
            },
          });
          return entries;
        },
      },
    },
    Author: {
      postCount: {
        type: "Int!",
        resolve: async (source, args, context) => {
          const { totalCount } = await context.nodeModel.findAll({
            type: "BlogPost",
            query: {
              filter: { author: { id: { eq: source.id } } },
            },
          });
          return totalCount;
        },
      },
    },
  };

  createResolvers(resolvers);
};

Build Configuration APIs

Customize Babel and Webpack configurations for the build process.

/**
 * Modify Webpack configuration
 */
interface CreateWebpackConfigArgs extends ParentSpanPluginArgs {
  stage: WebpackStage;
  rules: WebpackRules;
  loaders: WebpackLoaders;
  plugins: WebpackPlugins;
  actions: Actions;
}

type WebpackStage = 
  | "develop"
  | "develop-html" 
  | "build-javascript"
  | "build-html";

interface WebpackRules {
  js: () => object;
  eslint: () => object;
  yaml: () => object;
  fonts: () => object;
  images: () => object;
  media: () => object;
  miscAssets: () => object;
}

interface WebpackLoaders {
  json: () => object;
  yaml: () => object;
  null: () => object;
  raw: () => object;
  style: () => object;
  css: () => object;
  postcss: () => object;
  file: () => object;
  url: () => object;
  js: () => object;
  dependencies: () => object;
}

Usage Examples:

// gatsby-node.js - Webpack customization
exports.onCreateWebpackConfig = ({ stage, loaders, actions, plugins }) => {
  const { setWebpackConfig } = actions;

  // Add custom webpack configuration
  setWebpackConfig({
    resolve: {
      alias: {
        "@components": path.resolve(__dirname, "src/components"),
        "@utils": path.resolve(__dirname, "src/utils"),
        "@images": path.resolve(__dirname, "src/images"),
      },
    },
  });

  // Stage-specific configuration
  if (stage === "build-html" || stage === "develop-html") {
    setWebpackConfig({
      module: {
        rules: [
          {
            test: /canvas/,
            use: loaders.null(),
          },
        ],
      },
    });
  }

  // Add custom loader
  if (stage === "develop" || stage === "build-javascript") {
    setWebpackConfig({
      module: {
        rules: [
          {
            test: /\.md$/,
            use: [
              loaders.js(),
              {
                loader: "frontmatter-markdown-loader",
                options: { mode: ["body"] },
              },
            ],
          },
        ],
      },
    });
  }
};

// Babel configuration
exports.onCreateBabelConfig = ({ actions }) => {
  actions.setBabelPlugin({
    name: "@babel/plugin-proposal-export-default-from",
  });

  actions.setBabelPreset({
    name: "babel-preset-gatsby",
    options: {
      targets: {
        browsers: ["> 1%", "last 2 versions", "IE >= 9"],
      },
    },
  });
};

Actions API

Available actions for manipulating pages, nodes, and build configuration.

/**
 * Actions available in gatsby-node.js APIs
 */
interface Actions {
  /** Page management */
  createPage: (args: CreatePageArgs) => void;
  deletePage: (args: DeletePageArgs) => void;
  createSlice: (args: CreateSliceArgs) => void;
  
  /** Node management */
  createNode: (node: NodeInput) => void;
  deleteNode: (node: { id: string }) => void;
  touchNode: (node: { id: string }) => void;
  createNodeField: (args: CreateNodeFieldArgs) => void;
  createParentChildLink: (args: CreateParentChildLinkArgs) => void;
  
  /** Build configuration */
  setWebpackConfig: (config: object) => void;
  replaceWebpackConfig: (config: object) => void;
  setBabelOptions: (options: object) => void;
  setBabelPlugin: (args: SetBabelPluginArgs) => void;
  setBabelPreset: (args: SetBabelPresetArgs) => void;
  
  /** Schema management */
  createTypes: (typeDefs: string | object) => void;
  createFieldExtension: (args: CreateFieldExtensionArgs) => void;
  addThirdPartySchema: (args: AddThirdPartySchemaArgs) => void;
  printTypeDefinitions: (args: PrintTypeDefinitionsArgs) => void;
  
  /** Jobs and processing */
  createJob: (job: JobInput, plugin?: IGatsbyPlugin) => void;
  createJobV2: (job: JobV2Input, plugin?: IGatsbyPlugin) => void;
  setJob: (job: Job, plugin?: IGatsbyPlugin) => void;
  endJob: (job: Job, plugin?: IGatsbyPlugin) => void;
  
  /** Other actions */
  createRedirect: (redirect: RedirectInput) => void;
  setPluginStatus: (status: object, plugin?: IGatsbyPlugin) => void;
  setRequestHeaders: (headers: Record<string, string>) => void;
  addGatsbyImageSourceUrl: (url: string) => void;
  unstable_createNodeManifest: (args: CreateNodeManifestArgs) => void;
  addRemoteFileAllowedUrl: (url: string | RegExp) => void;
  enableStatefulSourceNodes: () => void;
}

Adapter System

Modern deployment adapter system for various hosting platforms.

/**
 * Adapter initialization function
 */
type AdapterInit = (options?: object) => IAdapter;

/**
 * Adapter interface for deployment platforms
 */
interface IAdapter {
  name: string;
  cache: Cache;
  config: IAdapterConfig;
  initializeAdapterStore?: () => Promise<void>;
  createRoutes?: (functions?: Array<IFunctionDefinition>) => Promise<RoutesManifest>;
}

interface IAdapterConfig {
  deployURL?: string;
  excludeDatastoreFromBundle?: boolean;
  imageCDN?: boolean;
  fileCDN?: boolean;
}

interface IFunctionDefinition {
  functionId: string;
  originalFilePath: string;
  relativeCompiledFilePath: string;
  absoluteCompiledFilePath: string;
  matches: Array<string>;
}

interface RoutesManifest {
  version: 1;
  routes: Array<IStaticRoute | IFunctionRoute | IRedirectRoute>;
  headers?: HeaderRoutes;
  functions?: FunctionsManifest;
}