Skip to content

feat(cli): migrate template loading to Giget #100

Description

@domutala

Context

The Runable CLI is responsible for creating new projects from official starters.

As Runable supports multiple server runtimes and backend frameworks, the number of starters is expected to grow over time, including NestJS, Fastify, Express, Hono, AdonisJS, and potentially other runtimes.

The CLI therefore needs a reliable and extensible way to retrieve, extract, and manage project templates without maintaining unnecessary custom infrastructure.

Problem

The current CLI relies on custom logic to retrieve and prepare project templates.

As the number of official Runable starters grows, maintaining this logic increases the complexity of the CLI and introduces responsibilities that are not specific to Runable itself, such as:

  • downloading template archives;
  • extracting templates;
  • resolving remote template sources;
  • handling temporary files;
  • handling download and extraction errors;
  • potentially managing caching.

This makes the project creation layer harder to maintain and increases the amount of infrastructure code required when adding new starters.

Template retrieval should be a small, well-defined responsibility that can rely on an existing and proven solution.

Proposed solution

Use Giget as the template retrieval layer for the Runable CLI.

Giget would be responsible for downloading and extracting starters, while the Runable CLI would remain responsible for the Runable-specific project creation flow:

  1. Collect project options.
  2. Select the appropriate starter.
  3. Resolve the target directory.
  4. Resolve the template source.
  5. Delegate template retrieval and extraction to Giget.
  6. Apply Runable-specific transformations if necessary.
  7. Install dependencies.
  8. Display the final project instructions.

Template definitions should also be centralized so that adding a new official starter requires minimal changes to the CLI.

The migration should preserve the existing CLI experience and package-manager behavior.

Example API

import { downloadTemplate } from "giget";

const templates = {
  nest: "gh:runablejs/runable-nest-starter",
  fastify: "gh:runablejs/runable-fastify-starter",
  express: "gh:runablejs/runable-express-starter",
  hono: "gh:runablejs/runable-hono-starter",
} as const;

type Template = keyof typeof templates;

async function createProject(
  template: Template,
  targetDir: string,
): Promise<void> {
  await downloadTemplate(templates[template], {
    dir: targetDir,
  });
}

Alternatives considered

Keep the current custom implementation

The CLI could continue maintaining its own template download and extraction logic.

This avoids introducing another dependency, but it also means maintaining infrastructure that is not specific to Runable and that will become more important as the starter ecosystem grows.

Use git clone

Official starters could be cloned directly from their Git repositories.

This is simple, but introduces a dependency on Git being available on the user's machine and exposes Git-specific behavior that is unnecessary for project scaffolding.

Implement a custom template registry and downloader

Runable could build its own registry and template retrieval system.

This would provide complete control, but would duplicate functionality already provided by specialized tooling and introduce additional maintenance cost.

Benefits

This migration would provide several benefits:

  • Reduce custom infrastructure inside the Runable CLI.
  • Make template retrieval more reliable and easier to maintain.
  • Simplify the addition of new official starters.
  • Keep template definitions centralized.
  • Avoid requiring Git for standard template downloads.
  • Provide a cleaner separation between project scaffolding and Runable-specific CLI logic.
  • Benefit from a mature template retrieval solution already used across the UnJS/Nuxt ecosystem.
  • Make the CLI easier to test by isolating template resolution from project creation.
  • Prepare the CLI for a growing ecosystem of Runable starters.

Additional context

Giget is maintained within the UnJS ecosystem and is designed specifically for downloading and extracting project templates.

Repository:
https://github.com/unjs/giget

The migration should not change the expected developer experience:

npm create runable@latest my-app

The selected starter should be retrieved through Giget transparently.

Implementation should also include:

  • migration of the existing template retrieval logic;
  • a centralized and strongly typed template registry;
  • clear error handling for unavailable or invalid templates;
  • tests for template resolution and retrieval;
  • tests for download failures;
  • updates to existing CLI tests where necessary;
  • documentation updates where necessary;
  • a changeset if the migration introduces a user-facing change.

The goal is not to expose Giget as part of Runable's public API. Giget should remain an internal implementation detail of the CLI.

Before submitting

  • I searched existing issues and discussions for similar proposals.
  • This request describes a concrete use case rather than only an implementation preference.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions