Create a custom template

IDX offers a wide range of built-in templates that include all the files, system packages (e.g. compilers), and extensions a user may need to quickly get started with a language or framework.

You may also want to create your own, user-configurable templates. For example:

  • If you're building your own framework, library, or service, you can allowing your users to quickly get started with your technology, without leaving the browser, with the full power of a cloud-based virtual machine.

  • If you have a preferred technology stack for your projects, you can simplify your own process for starting new projects with a custom template.

  • If you're teaching others, such as through a codelab, you can remove some of the initial steps for your students by pre-configuring the starting point for your codelab as a custom template.

Once you have a custom template ready, you can then create a link for it to place on your website, Git repository README file, package detail page (e.g. in NPM), or other places from which users may want to get started with your technology.

Prerequisites

Before getting started, make sure you're familiar with customizing your environment with .idx/dev.nix files.

Templates also use the Nix language, so you may want to brush up on some of the basics, or keep it handy as a reference.

Template file structure

A template is a public GitHub repository (or folder or branch in a repository) that contains at least two files:

  • Dialog users see when they create a new workspace from your template
    Creating a new workspace from a custom template

    idx-template.json includes the metadata for the template, including its user-visible name, description, and parameters available to users to configure the template. For example, you can allow your users to choose from a number of programming languages, or example use cases. IDX uses this information to prepare the UI shown to users when they choose to create a new workspace from your template.

  • idx-template.nix is a file written with the Nix language that contains a Bash shell script (wrapped in a Nix function) responsible for:

    1. Creating the new workspace's working directory and
    2. Setting up its environment by creating a .idx/dev.nix file. Note that you can also just run a project scaffolding tool like flutter create or npm init in this script, or run a custom script written in Go, Python, Node.js, or another language.

    This file will be executed with the parameters specified by the user when they configured the template.

Other files may be included alongside these two files, for use in idx-template.nix, in order to instantiate the template. For example, you could include the final .idx/dev.nix file, or even include all of the scaffolding files right in the repository.

A basic example: turn any public GitHub repository into a template

Before getting into the details of how to define your idx-template.json and idx-template.nix, it's useful to see a basic example template that:

  • Has no user-configurable parameters
  • Just copies all the files in your template repository (except for the two idx-template files) into the user's workspace. There should already be a .idx subfolder with a dev.nix file defining the environment.

Adding the following files to any public GitHub repository (or subfolder or branch) effectively turns that repository into an IDX template.

idx-template.json

{
  "name": "Hello world",
  "description": "A template for a CLI program that prints 'hello world'",
  "icon": "https://www.gstatic.com/images/branding/productlogos/idx/v1/192px.svg",
  "params": []
}

idx-template.nix

# No user-configurable parameters
{ pkgs, ... }: {
  # Shell script that produces the final environment
  bootstrap = ''
    # Copy the folder containing the `idx-template` files to the final
    # project folder for the new workspace. ${./.} inserts the directory
    # of the checked-out Git folder containing this template.
    cp -rf ${./.} "$out"

    # Set some permissions
    chmod -R +w "$out"

    # Remove the template files themselves and any connection to the template's
    # Git repository
    rm -rf "$out/.git" "$out/idx-template".{nix,json}
  '';
}

Use additional system packages in your bootstrap script

The previous example only uses basic POSIX commands to copy files into the right place. Your template's bootstrap script may require additional binaries to be installed, such as git, node, python3, or others.

You can make additional system packages available to your bootstrap script by specifying packages in your idx-template.nix file, just as you would customize a workspace with additional system packages by adding to the packages in its dev.nix file.

Here's an example of adding pkgs.nodejs, which includes binaries like node, npx and npm:

# idx-template.nix
{pkgs}: {
  packages = [
    # Enable "node", "npm" and "npx" in the bootstrap script below.
    # Note, this is NOT the list of packages available to the workspace once
    # it's created. Those go in .idx/dev.nix
    pkgs.nodejs
  ];

  bootstrap = ''
    mkdir "$out"
    # We can now use "npm"
    npm init --yes my-boot-strap@latest "$out"
  ''
}

Add user-configurable parameters

To allow users to customize the starting point for their new project, you can either create multiple templates, or create a single template with parameters. This is a great option if your different starting points are just different values passed to a CLI tool (for example --language=js versus --language=ts).

To add parameters, you'll:

  1. Describe your parameter in the params object of your idx-template.json metadata file. IDX uses information in this file to prepare the UI (such as checkboxes, drop-downs, and text fields) shown to users of your template.
  2. Update your idx-template.nix bootstrap to use the values the user selected while instantiating the template.

Describe your parameter in idx-template.json

Here's an example of adding an enum parameter, which IDX shows as either a drop-down menu or radio button group, depending on the number of options.:

{
  "name": "Hello world",
  "description": "A hello world app",
  "params": [
    {
      "id": "language",
      "name": "Programming Language",
      "type": "enum",
      "default": "ts",
      "options": {
        "js": "JavaScript",
        "ts": "TypeScript"
      },
      "required": true
    }
  ]
}

Since there are two values (JavaScript and TypeScript), the UI will render a radio button group for the two options and pass either the value ts or js to the idx-template.nix script.

Each parameter object has the following properties:

PROPERTY TYPE DESCRIPTION
id string The parameter's unique ID, similar to a variable name.
name string The display name for this parameter.
type string

Specifies the UI component to use for this parameter, and the data type to pass to the bootstrap script. Valid values are:

  • "enum" - Shows a drop-down or radio button group, and passes a string to the bootstrap
  • "boolean" - Shows a checkbox and passes true or false
  • "text" - Shows a text field and passes a string
options object For enum parameters, this represents the options to show users. For example if options is {"js": "JavaScript", ...}, "JavaScript" will be shown as the option, and when selected the value of this parameter will be js.
default string or boolean Sets the initial value in the UI. For enum parameters, this must be one of the keys in options. For boolean parameters, this should be either true or false.
required boolean Indicates that this parameter is required.

Use parameter values in idx-template.nix

After defining the params object in your idx-template.json file, you can start customizing the bootstrap script based on the parameter values the user chooses.

Following the example in the previous section, if you have a single parameter with ID language that's an enum with possible values ts or js, you can use it like so:

# idx-template.nix
# Accept additional arguments to this template corresponding to template
# parameter IDs, including default values (language=ts by default in this example).
{ pkgs, language ? "ts", ... }: {
  packages = [
    pkgs.nodejs
  ];

  bootstrap = ''
    # We use Nix string interpolation to pass the user's chosen programming
    # language to our script.
    npm init --yes my-boot-strap@latest "$out" -- --lang=${language}
  ''
}

Another common pattern is to conditionally include content depending on the value of a string. Another way to write the previous example is:

npm init --yes my-boot-strap@latest "$out" -- \
    ${if language == "ts" then "--lang=ts" else "--lang=js" }

Choose which files should open by default

It's a good idea to customize which files should be opened for editing when new workspaces are created with your template. For example, if your template is for a basic website, you may want to open the main HTML, JavaScript and CSS files.

To customize which files should open by default, update your .idx/dev.nix file (not your idx-template.nix file!) to include an onCreate workspace hook with an openFiles attribute, like so:

# .idx/dev.nix
{pkgs}: {
  ...
  idx = {
    # Workspace lifecycle hooks
    workspace = {
      # Runs when a workspace is first created with this `dev.nix` file
      
        # Open editors for the following files by default, if they exist.
        # The last file in the list will be focused.
        default.openFiles = [
          "src/index.css"
          "src/index.js"
          "src/index.html"
        ];
        # Include other scripts here, as needed, for example:
        # installDependencies = "npm install";
      };
      # To run something each time the workspace is (re)started, use the `onStart` hook
    };
    # Enable previews and customize configuration
    previews = { ... };
  };
}

Create a new workspace from your template

The simplest way to test your template end-to-end is to create a new workspace with it. Visit the following link, replacing the example with your template's GitHub repository URL:

https://idx.google.com/new?template=https://github.com/my-org/my-repo

You can optionally include a branch and subfolder. All of the following are valid, as long as they are publicly accessible:

  • https://github.com/my-org/my-repo/
  • https://github.com/my-org/my-repo/tree/main/path/to/myidxtemplate
  • https://github.com/my-org/my-repo/tree/branch
  • https://github.com/my-org/my-repo/tree/branch/path/to/myidxtemplate

This is also the URL you'll share with others so that they can use your new template, or the URL you'll link to from your "Open in IDX" button.


Share your template

Once you've confirmed that your template behaves as expected, publish it to a GitHub repository and share the same link you used when creating a workspace for testing.

And to make it even easier for users to find your template, add an "Open in IDX" button to your website or repository README.