Model or dataset
jordan-dalby/ByteStash avatar
jordan-dalby/ByteStash

ByteStash: A Self-Hosted Code Snippet Manager You Run Yourself

A code snippet storage solution written in React & node.js

2,541 stars123 forksTypeScriptGPL-3.0

At a glance

What is it?
ByteStash is a React and Node.js web app that stores code snippets in a SQLite database on your own hardware. It is aimed at developers who want snippet search, an API and an MCP endpoint without handing their code to a SaaS vendor.
Who is it for?
Adopt ByteStash if you already run Docker or Unraid and want snippet storage you control, with an API and MCP endpoint for AI assistants. Skip it if you need a hosted service with no server to manage, or if you want a desktop editor plugin rather than a browser app.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 3 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 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What ByteStash Solves, and Who It Is Actually For

Snippets accumulate in scattered places: a notes app here, a gist there, a comment buried in a project. ByteStash is a self-hosted web application for storing, organising and managing code snippets, according to its README. The pitch is consolidation plus ownership. Everything lives in a SQLite database on a machine you control, and the README's feature list puts "Secure Storage" in those terms: snippets are stored in SQLite and reachable only by you.

The audience is narrow but real. You need to be comfortable running a container, or willing to use a hosted option. The README points at three deployment routes: the Unraid App Store, PikaPods for a one-click install, and a manual docker-compose file. Someone who wants a snippet tool but has no server and no interest in one is not the target. Someone who already runs a homelab, a Proxmox box, or a small VPS is.

The feature set is deliberately small. Create and edit snippets. Filter by language or by keywords in the content. That is the core loop. The README does not describe tagging, folders, nested collections, sharing links, or version history, so do not expect them. If your snippet collection is large enough that you need hierarchy, this is a flat store with a search box, and you should weigh that before migrating anything into it.

How ByteStash Is Built: React, Express, SQLite, One Port

The repository is a two-workspace monorepo. The root package.json declares workspaces for client and server, with the entry point at server/app.js and an engine requirement of Node.js 22 or newer. The README's tech stack section names React and Tailwind CSS on the frontend, Node.js and Express on the backend, and Docker for containerisation.

The Dockerfile shows the actual data flow. A first stage builds the client from node:22-alpine and emits static assets into /app/client/build. The production stage installs only server dependencies with npm install --omit=dev, copies server/src and server/docs, then copies the built client into /client/build. The final command is node src/app.js. So the Express server is serving the compiled React bundle, the REST API, and the MCP endpoint from the same process.

That single-process design explains the port layout. The compose file maps 5000:5000 and its comment states plainly that this port serves the web UI, the REST API under /api, and the remote MCP endpoint at /mcp. There is no separate frontend container and no second port to expose. The Dockerfile also creates ./data/snippets, which is where the SQLite database lives and why the compose file mounts /your/snippet/path to /data/snippets.

One build detail is worth noting because it is unusual to see documented. The client-build stage is pinned with FROM --platform=$BUILDPLATFORM, and the comment explains why: the client build emits architecture-independent static assets, so building under QEMU emulation for arm/v7 wastes time and hits Node's roughly 1GB 32-bit heap cap. That is a considered choice, not an accident.

Installing ByteStash with Docker Compose and Adding a First Snippet

The README gives three install paths. Unraid users install from the Unraid App Store. PikaPods offers a one-click install starting at $1/month. For manual hosting, the README supplies a docker-compose file. The repository also ships docker-compose.yaml at the top level, which is the more complete of the two.

The repository's compose file builds from the local Dockerfile rather than pulling an image. The README's version pulls ghcr.io/jordan-dalby/bytestash:latest instead. Both are valid; the README form is shorter for a first run, so start there. Save this as docker-compose.yaml and change the volume path on the left to a directory you actually back up.

yaml
services:
  bytestash:
    image: "ghcr.io/jordan-dalby/bytestash:latest"
    restart: always
    volumes:
      - /your/snippet/path:/data/snippets
    ports:
      - "5000:5000"
    environment:
      BASE_PATH: ""
      TOKEN_EXPIRY: 24h
      ALLOW_NEW_ACCOUNTS: "true"
      DEBUG: "true"
      DISABLE_ACCOUNTS: "false"
      DISABLE_INTERNAL_ACCOUNTS: "false"

Run it in the background and follow the logs for the first start.

bash
docker compose up -d
docker compose logs -f bytestash

The app listens on port 5000, so open http://localhost:5000 in a browser. With ALLOW_NEW_ACCOUNTS set to true you can register the first account. Once you have logged in, create a snippet through the UI and give it a language. The language value is what the filter uses later, so it is worth being consistent from the first entry.

If you are putting ByteStash behind a reverse proxy on a subpath, set BASE_PATH to that subpath, for example /bytestash for a domain like my.domain/bytestash. Leave it blank in every other case. The compose file's comment is explicit about this. For proxies that rewrite the Host header, ALLOWED_HOSTS takes a comma-separated list such as localhost,my.domain.com,my.domain.net.

Once the server is running, the README says you can explore the API in a browser at /api-docs, which serves Swagger UI for all endpoints.

The MCP Endpoint and What It Changes About Snippet Retrieval

The most distinctive part of ByteStash is that it exposes a remote Model Context Protocol endpoint, so assistants such as Claude, OpenAI/ChatGPT and Perplexity can search, read and manage snippets directly. The endpoint lives at https://<your-host>/mcp, or https://<your-host><BASE_PATH>/mcp when a base path is configured. It runs on the same host and port as the app, so nothing extra needs exposing.

Authentication reuses the REST API key. You create one under Settings, then API Keys in the UI, and send it as Authorization: Bearer <api-key> or as the x-api-key header. The README states that the MCP tools only ever access snippets owned by that key, which is the scoping guarantee to rely on if you hand a key to an assistant.

The tool surface is small and CRUD-shaped: list_snippets, get_snippet, create_snippet, update_snippet, delete_snippet and list_metadata. Transport is Streamable HTTP. Client configuration for Claude Desktop goes in claude_desktop_config.json:

json
{
  "mcpServers": {
    "bytestash": {
      "type": "http",
      "url": "https://your-host/mcp",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}

The README also documents the OpenAI Responses API shape, where the server is passed as an MCP tool with type, server_label, server_url and headers fields, and notes that Perplexity takes a remote MCP connector with the same URL and Authorization header. Claude.ai and other web clients use a custom connector.

There is a hard constraint stated in a callout: the endpoint requires HTTPS for remote clients, and you are expected to terminate TLS at your reverse proxy or ingress, the same way you already do for the web UI. An assistant that can create and delete snippets is a write path into your database, so that requirement is not decorative.

Where ByteStash Is the Wrong Tool

The README does not document snippet versioning, sharing, or export. It mentions export only obliquely, in the description of DISABLE_ACCOUNTS, which warns that enabling it is like starting a fresh account and tells you to export your snippets first. There is no documented import path and no documented rollback if a bad edit or a misbehaving MCP client deletes something. Your SQLite file in the mounted volume is the backup. If you have not arranged one, you have no recovery story.

The account model has sharp edges too. DISABLE_ACCOUNTS removes login entirely, and DISABLE_INTERNAL_ACCOUNTS turns off local accounts, presumably for deployments that rely on OIDC instead. Setting either on a publicly reachable instance without understanding the consequence is a way to expose every snippet you have stored. The README's compose file defaults ALLOW_NEW_ACCOUNTS to true, which is convenient for a first run and wrong for anything on the open internet.

Scale is the other boundary. SQLite plus a single Express process is a good fit for one person or a small team. The README gives no guidance on concurrent writers, database size, or multi-instance deployment, and the architecture as shown in the Dockerfile is a single process serving the UI, the API and MCP together. If you need horizontal scaling or per-team permissions, this is not the shape you want.

Finally, the README documents no tagging or folder system. Filtering by language and by content keywords is the whole retrieval model. Past a few hundred snippets, that may be enough. Past a few thousand, it probably is not.

Alternatives: massCode and Kara Keep Take Different Roads

The two names that come up alongside ByteStash are massCode and Kara Keep, and the architectural difference matters more than the feature lists.

massCode is a desktop application. It runs on your machine as an installed program rather than as a server you reach over HTTP. That means no container, no reverse proxy, no TLS termination, and no port to expose. It also means no remote MCP endpoint reachable by a hosted assistant, and no browser access from a second device unless you add your own sync. If your snippets should never leave the laptop, that is a feature. If you want to pull a snippet into a chat with Claude from your phone, it is a wall.

Kara Keep is the other direction: a hosted service rather than something you run. You trade the operational work of Docker, volumes, backups and upgrades for a subscription and for your snippets living on someone else's infrastructure. ByteStash's README explicitly frames its storage as keeping code in one secure place you control, and that framing is the entire reason to pick it over a hosted alternative. If you do not care about that, you are paying in maintenance time for a guarantee you did not want.

The honest summary: ByteStash sits between a local desktop tool and a SaaS product. It is for people who want the browser and API access of a hosted service but the data ownership of a local app, and who accept running a container as the price.

Maintenance Cost, Upgrades and the GPL-3.0 Licence

ByteStash is not archived, and the last push was on 2026-09-28. Releases are frequent: v1.5.11 on 2026-02-03, v1.5.12 on 2026-06-19, and v1.5.13 on 2026-09-28. That cadence tells you the project is being worked on, but it also means upgrades arrive often enough that you should decide on a policy rather than upgrading reactively.

The upgrade mechanics are simple because of the image tag. The README's compose file uses ghcr.io/jordan-dalby/bytestash:latest, so a pull followed by a recreate moves you forward. There is no documented migration step and no documented rollback procedure, which is the part to plan around: snapshot the directory you mounted at /data/snippets before you pull, because that directory holds the SQLite database. If a release changes the schema and something goes wrong, the snapshot is your only documented way back.

The repository also ships helm-charts/ and a Dockerfile.dev plus docker-compose-dev.yaml, so Kubernetes users have a path and contributors have a development setup. The contributing section describes the i18n workflow in detail: add a locale to the Locale enum in client/src/i18n/types.ts, add it to the locales array in client/i18next.config.ts, run npm run i18n:extract from the client directory, replace the __TRANSLATE_ME__ lines, create client/src/i18n/resources/fr.ts, and update the export in client/src/i18n/resources/index.ts. That is a concrete, followable process, which is more than many projects offer.

On licensing, ByteStash is GPL-3.0. Running it for yourself or your team is the ordinary case. If you intend to modify it and distribute the result, or to embed it in a product, the copyleft terms apply and you should read the LICENSE file in the repository rather than take a summary from an article. This is not legal advice.

Editorial conclusion

Adopt ByteStash if you already run Docker or Unraid and want snippet storage you control, with an API and MCP endpoint for AI assistants. Skip it if you need a hosted service with no server to manage, or if you want a desktop editor plugin rather than a browser app. Before committing, verify that your reverse proxy terminates HTTPS for the /mcp endpoint, that the /your/snippet/path volume is backed up, and that ALLOW_NEW_ACCOUNTS is set to false on any instance reachable from the internet.

Frequently asked questions

What is a self-hosted code snippet manager, and is ByteStash one?

It is software you run on your own machine or server that stores code snippets for you, rather than a service someone else operates. ByteStash fits that description: the README describes it as a self-hosted web application that stores snippets in a SQLite database on your hardware.

What port does ByteStash use by default?

Port 5000. The README's docker-compose file maps 5000:5000, and the repository's Dockerfile ends with EXPOSE 5000. The same port serves the web UI, the REST API under /api, and the MCP endpoint at /mcp.

How do I install ByteStash with Docker Compose?

Use the docker-compose file in the README, which pulls ghcr.io/jordan-dalby/bytestash:latest, mounts a host directory to /data/snippets, and maps port 5000. Set BASE_PATH if you serve it from a subpath, and ALLOWED_HOSTS if your reverse proxy rewrites the Host header.

How do I back up ByteStash snippets?

The README does not document a backup command. Snippets are stored in a SQLite database inside the mounted volume, which the README's compose example maps as /your/snippet/path:/data/snippets, so that directory is what you need to preserve.

Does ByteStash work with Claude, OpenAI and Perplexity?

Yes, through the MCP endpoint. The README states that ByteStash exposes a remote Model Context Protocol endpoint at https://<your-host>/mcp using Streamable HTTP, authenticated with the same API key as the REST API, and gives configuration examples for Claude Desktop, the OpenAI Responses API and Perplexity.

How do I connect ByteStash to Authentik for single sign-on?

Through the OIDC environment variables. The compose file lists OIDC_ENABLED, OIDC_DISPLAY_NAME, OIDC_ISSUER_URL, OIDC_CLIENT_ID and OIDC_CLIENT_SECRET, and its comment gives an Authentik issuer URL of the form https://authentik.mydomain.com/application/o/bytestash/. The README points to a wiki page for the full setup.

Official sources

  1. Issues
  2. jordan-dalby/ByteStash on GitHub
  3. License: GPL-3.0
  4. README
  5. Releases
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/jordan-dalby-bytestash.svg)](https://hysenlabs.com/projects/jordan-dalby-bytestash)