CLI tool
roninoss/create-expo-stack avatar
roninoss/create-expo-stack

create-expo-stack runs as rn-new and ships two packages in lockstep

CLI tool to initialize a React Native application with Expo. Provides options to include Typescript, file-based routing via Expo Router, configuration based routing via pure React Navigation, styling via Nativewind, Restyle, Unistyles, StyleSheets, or Tamagui, and/or backend as a service such as Firebase and Supabase.

2,576 stars117 forksTypeScriptMIT

At a glance

What is it?
An interactive CLI that scaffolds a React Native and Expo application, with sixteen library versions pinned across its templates and files assembled per file from a base folder plus optional package folders using EJS. Its repository name, its two published package names and its invocation command are three different things, and its own description advertises two styling options the page never mentions.
Who is it for?
This CLI is worth reaching for if you want a typed Expo app with your choice of routing and styling already wired, because the per-file template mechanism means you get a project rather than a starting point to unpick. Three things to check first.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 19 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 4, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Three names for one tool, and two packages released together

The names do not line up, and that matters before you type anything.

The repository is `create-expo-stack`. The command you run is not that. It is `npx rn-new@latest`, and the short domain the project uses as its homepage corresponds to that same short name.

There is also a second published package. Of the three recent releases, two carry the version 2.23.3 at the same moment: one named `rn-new`, the other named `create-expo-stack`. The third is `rn-new` at 2.23.2.

So the tool ships as two npm packages, released in lockstep at the same version and the same timestamp. That is deliberate, and it is why the same installation appears under both names. It also means if you depend on one and pin it, the other is a version behind or ahead depending on which publish failed, and neither package's changelog will tell you about the other's changes.

Underneath, this is a monorepo with four workspaces: the CLI itself, a landing site, a documentation site, and the second package. Every one of those has its own build filter in the root scripts, including separate targets for the landing site, the docs, and the second package. Four workspaces, one user-facing command.

The description advertises two styling options the page drops

The repository description and the page disagree about what you can choose.

The description says the CLI can configure styling via Nativewind, Restyle, Unistyles, StyleSheets, or Tamagui. Five options.

The page's own description section says styling with Nativewind, Unistyles, or StyleSheets. Three. The version table that follows backs up the page rather than the description: it lists Nativewind at a specific version and Unistyles at a specific version, and no row for Restyle and no row for Tamagui at all.

So two of the five advertised options have no entry in the table of versions the page provides. That is not proof they are unavailable, since the table explicitly covers only what the templates currently use. But the table is the part a reader uses to decide, and it does not mention them.

The same gap appears in the routing choice, though more mildly. The description says file-based routing via Expo Router or configuration-based routing via pure React Navigation, and the table confirms both by listing Expo Router and React Navigation at pinned versions. So routing is described consistently in both places, which makes the styling discrepancy stand out as the outlier rather than as a general pattern of loose wording.

The version table carries superlatives and a typo

The library table has three columns, and the third one is not purely descriptive.

Two entries are superlatives. React Native is labelled the best cross-platform mobile framework, and React is labelled the most popular UI framework in the world. Unistyles is described as a superset of StyleSheet, which is a specific and checkable claim rather than a boast, and Supabase as an open source Firebase alternative, which is a positioning statement.

A version table is a reference artefact. Its job is to tell you what is in the generated project, and superlatives do not do that job; they tell you what the author thinks of the library. They also date badly, because the most popular framework changes over time and a pinned table does not.

There is also a spelling error in the Expo row, where the SDK is described as an opinionated framework for building React Native apps, with the word misspelled. That row matters more than its neighbours, because the Expo SDK version is the single most consequential number in the table. It is what determines which React Native version works, which determines which React version works.

Sixteen rows in total, each with a version, and the note above them says all templates use the same versions, that not every template includes every library, and that all of them remain available for use. That is a genuinely useful clarification, because it distinguishes the version set from the inclusion set.

It develops with Bun and generates projects for four managers

The repository declares Bun as its package manager at a specific pinned version, and the lockfile at the root is Bun's binary lockfile format. A contributor script is also invoked through Bun.

The generated projects, meanwhile, can target four different package managers. The page says the CLI attempts to determine your package manager of choice automatically, and that you can override it by passing a flag for npm, yarn, pnpm or bun.

So the detection logic has to handle the manager this project itself uses plus three others, and the default it picks on your machine depends on what is already there. That is a reasonable design and also the source of the one surprise in the quick start: a contributor on the project who has Bun installed will get a Bun project, and a user with nothing installed gets whatever the detection falls back to.

The flag list is short and worth knowing in full. There is a flag to skip installing dependencies, a flag to skip initialising a repository, and a flag to take defaults rather than prompting. So the entire interactive session can be bypassed, which is what you want in a script or a CI job, and the page does not spell out what defaults means beyond the name.

The invocation itself is deliberately unpinned to a major, using the latest tag, so a fresh install picks up whatever was published most recently rather than a version you chose.

Templates are assembled per file from two folders and EJS

This is the mechanism worth understanding, because it is what makes the CLI extensible rather than a set of hardcoded branches.

Each generated project is produced file by file according to the answers given to the CLI. Files common to every generated project live in a base template folder. Files that belong to optional packages live in a separate packages template folder.

So choosing Firebase adds files from the packages folder; choosing nothing does not. And because the common files live in one place, every generated project starts from an identical baseline, which is what keeps sixteen template permutations from drifting apart.

The second half of the mechanism is that adding a file is not the only operation. The project uses EJS to manipulate existing files as necessary. That matters for the cases a file-copy approach cannot handle: inserting an import line into an existing file, adding a provider to a wrapper, or commenting out a block when an option is off.

The page states plainly that this per-file approach is what makes the CLI easy to extend. It is also the part with no documentation on the page. Nothing here describes how to add a template folder, what variables the templates receive, or what happens when a base file and a package file both want to write the same path. Those are the questions anyone extending this would have to answer by reading the source, and the templates directory is linked from the page as the place to start.

TypeScript is pinned to latest in the repo that ships TypeScript templates

One line in the development dependencies is worth stopping on. TypeScript is declared as `latest`, with no version range at all.

Every other tool in that list is pinned to a minor or a range: the linting stack, the formatter, the changesets tooling, the task runner, and the TypeScript ESLint packages. The one floating dependency is the compiler, in a repository whose entire output is a set of templates for typed applications.

That is a reproducibility trade rather than an oversight. Floating the compiler means the templates can be validated against current TypeScript without a dependency bump, which is defensible for a scaffolding tool. It also means a TypeScript release can change what the templates compile to, or break the build, without anything in the repository changing to record it.

Two other version signals in the same file. The task runner is on its first major, and the linting stack is on ESLint 8 driven by a file in the legacy configuration format, referenced explicitly when formatting runs. The formatter's own settings are configured inline in the manifest rather than in a separate file, including a line width of 120 and no trailing commas.

The formatting script is broad. It runs the linter with fixes across JavaScript and TypeScript, and the formatter across a list that includes Astro, MDX, YAML and EJS, which tells you the landing site and documentation site are built with different technologies from the CLI itself.

A contributor cell renders the literal name Null

The contributors table is generated, and the generator left evidence of itself in the output.

The table is delimited by HTML comment markers naming it as a contributors section, matching a script in the repository that regenerates it, with the GitHub API client among the development dependencies. So the table is not written by hand and should not be edited by hand.

One of the cells displays the name Null in bold, next to a profile link that is present and working. Everything else about that cell is correct. Only the name is missing.

That is a script reading a field that was absent and rendering the absence as a literal string rather than skipping the cell. It is a small bug with a disproportionate signal value, because a contributor whose name renders as Null has a reason to look at their own row, and anyone reading the table has to decide whether that is a display fault or a missing contribution.

The same part of the page carries something else. After the contributing section there is a heading offering to help you move faster faster, stating that the maintainer may be available, and linking to a direct chat. It sits between the contribution instructions and the contributor credits.

That is a commercial arrangement described in the readme of an MIT-licensed tool, which is fine in itself. It does interact with the bug reporting section, which tells you to search issues and discussions first and then, if you find nothing, message the maintainer directly. So the escalation path for a bug is a private message rather than an issue, which is worth knowing before you rely on it.

Editorial conclusion

This CLI is worth reaching for if you want a typed Expo app with your choice of routing and styling already wired, because the per-file template mechanism means you get a project rather than a starting point to unpick. Three things to check first. Read the styling options in the page rather than in the repository description, because the two disagree: the page lists three styling choices and the description lists five, so at least two of them are not what this template set currently ships. Pin the package manager you want with an explicit flag instead of relying on detection, particularly since the tool detects Bun, which is what its own repository uses. And expect a project that pins sixteen libraries to exact versions, so upgrading later is a deliberate exercise rather than a matter of running an update. Treat the maintainer's offer of paid advisory help as a separate arrangement from the open source tool, and prefer issues and discussions for anything reproducible.

Frequently asked questions

How do I create an Expo project with create-expo-stack?

Run `npx rn-new@latest`. The CLI is interactive and prompts you to opt into features, and it also accepts flags such as `--noInstall`, `--noGit` and `--default` if you want to skip the prompts.

Which package managers can create-expo-stack generate projects for?

The CLI attempts to detect your package manager automatically, and you can override it with `--npm`, `--yarn`, `--pnpm` or `--bun`. The repository itself develops with Bun, pinned at 1.2.11, and its root lockfile is Bun's.

Which styling options does create-expo-stack support?

The page lists Nativewind, Unistyles and StyleSheets, and its version table includes Nativewind and Unistyles. The repository description additionally names Restyle and Tamagui, neither of which appears in the table.

How are the create-expo-stack templates structured?

Projects are generated file by file. Files common to every project live in a base template folder, files for optional packages live in a packages template folder, and EJS is used to manipulate existing files as necessary rather than only adding new ones.

Which libraries do the create-expo-stack templates include?

Sixteen pinned versions, including React Native v0.81, React v19.1, TypeScript v5.9, Expo SDK v54, Expo Router v6, React Navigation v7.1, Nativewind v4.1, Unistyles v3, React Native Web v0.21, Firebase v10.5 and Supabase v2.38. Not every template includes every library.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. roninoss/create-expo-stack on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/roninoss-create-expo-stack.svg)](https://hysenlabs.com/projects/roninoss-create-expo-stack)