Sub-Store: a self-hosted subscription manager for QX, Loon, Surge, Stash, Egern and Shadowrocket
Advanced Subscription Manager for QX, Loon, Surge, Stash, Egern and Shadowrocket!
At a glance
- What is it?
- Sub-Store is a JavaScript subscription manager that converts, filters and merges proxy subscriptions into one URL for a list of proxy clients. The README documents the conversion matrix and the operator pipeline, but leaves deployment and rollback largely to the wiki.
- Who is it for?
- Adopt Sub-Store if you already run several proxy clients and want one filtered, renamed subscription URL instead of editing node lists by hand; the operator pipeline and the format matrix are the reasons to bother. Skip it if you need a hosted service with an account system, or if you cannot run Node or a proxy-app module yourself, because the README points at the wiki for deployment and documents no rollback path.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Sub-Store fixes for people running several proxy clients
The problem is not a shortage of proxy nodes. It is that each client wants the same nodes written differently. Surge takes one syntax, Loon another, Quantumult X another, and mihomo another again. A provider hands you a URI list or a Clash YAML, and you then want to drop the expired nodes, rename the rest into a consistent scheme, and hand one URL to each device.
Sub-Store sits in the middle. The README describes it as an "Advanced Subscription Manager for QX, Loon, Surge, Stash, Egern and Shadowrocket", and the four core functions it lists are conversion between formats, subscription formatting, collecting multiple subscriptions behind one URL, and hosting or modifying subscriptions and files. The audience is therefore narrow and specific: someone who already knows which client they run, has more than one subscription source, and is willing to operate a small service rather than paste links into an app.
If you use one client and one provider, the tool is overhead. The value appears when the same node set has to be presented to two or three clients with different naming and filtering rules, and you want that presentation defined once.
The conversion matrix and the operator pipeline
Two mechanisms carry most of the work. The first is format translation. On the input side the README lists proxy URI schemes (socks5, socks5+tls, http, https), URI forms for AnyTLS, SOCKS, SS, SSR, VMess, VLESS, Trojan, Hysteria, Hysteria 2, TUIC v5 and WireGuard, Clash Proxies YAML, Clash proxy JSON/JSON5/YAML as a single line, plus the native export formats of QX, Loon, Surge and mihomo. On the output side it lists Plain JSON, Stash, Clash.Meta (mihomo), Surfboard, Surge, SurgeMac, Loon, Egern, Shadowrocket, QX, sing-box, V2Ray and V2Ray URI. Clash is marked deprecated: the README says the frontend no longer shows it, while the backend still accepts it through the query parameter target=Clash.
The second mechanism is the operator chain applied to the parsed node list. The README groups them into filtering (regex filter, discard regex filter, region filter, type filter, useless proxies filter, script filter) and proxy operations (set property, flag, sort, regex sort, regex rename, regex delete, script, resolve domain). Order matters here in the way it matters in any pipeline: a regex rename before a regex sort changes what the sort sees, and a resolve domain operator rewrites node addresses to IPs, which is useful when DNS resolution at the client is unreliable but also freezes an address that the provider may later move.
Two constraints are stated plainly. HTTP and HTTPS have no standard URI format, so the README says they are not supported as URI input and directs you to other formats. And it warns against exporting URIs from Shadowrocket or NekoBox and feeding them back in, because those exports may not be standard; some common non-standard URIs such as VMess and VLESS are handled anyway. The honest reading is that the input layer is tolerant, not universal.
Installing Sub-Store with pnpm and running the backend
The README's development section is short: install pnpm, then go to the backend directory. The repository layout shows backend/, config/ and scripts/ at the top level, with .node-version pinning the Node release. The README does not print the exact start command, so the block below stops where the documented steps stop.
npm install -g pnpm
cd backendAfter that, check .node-version and install a matching Node release before running anything in backend/. The README does not document the start script, the listening port or the data directory, so treat the wiki at github.com/sub-store-org/Sub-Store/wiki as the source for those rather than guessing.
For the module route, the README gives a concrete host mapping that keeps the rewrite domain local. The intent is that the module-script rewrite rules use sub.store, and mapping it to loopback stops a request that misses the rewrite from reaching the public service.
[Host]
sub.store = 127.0.0.1One configuration item is documented with a default and is worth setting deliberately. Node and server deployments read SUB_STORE_CORS_ALLOWED_ORIGINS, defaulting to https://sub-store.vercel.app,http://substore.stash,https://substore.stash. Proxy app modules take the same list through the cors module argument, with the same default. Origins are comma separated and matched exactly by scheme, host and port, and the README says to set the value to * only when you accept that any website can read the local backend through browser CORS. If your frontend is not the Vercel deployment, the default is the wrong value for you.
The sub.store notice is a design trade-off, not a footnote
Sub-Store's module rewrite rules use sub.store, and the README states that this domain is not owned by the project. The consequence it spells out: if a request does not go through the rewrite, the data goes to the public sub.store service. The README frames this as a data leakage risk and lists two possibilities, that the domain could in theory serve a fake frontend, and that it could receive user data. It also notes the official frontend is https://sub-store.vercel.app.
The project's response is to publish the notice and change nothing. The README says that after listening to suggestions it will not switch domains for now, because a replacement needs to be related, short, and unlikely to be registered by someone else in the short term. That is a defensible call about naming, but it leaves the mitigation with the user: map sub.store to 127.0.0.1 or another local address. The README is candid that ordinary users may still send requests to the public domain after switching or toggling configuration modules, so the mitigation reduces the window rather than closing it.
For a self-hosted Node deployment this matters less, because the rewrite path is a module concern. For anyone running Sub-Store as a proxy-app module, it is the first paragraph to read.
Where Sub-Store is the wrong tool
The README carries its own disclaimer: descriptions of features may not be updated in real time, and readers should refer to the actual available features. That is a maintenance statement about documentation drift, and it applies most to the long format lists, where a client's supported protocol set can move faster than a README table.
The harder limits are structural. Sub-Store is a manager, not a proxy. It does not provide nodes, and it does not tunnel traffic; it transforms and serves subscription data that another program consumes. If your provider already emits the exact format your client wants and you have no filtering or renaming to do, the operator pipeline adds a service to operate for no gain.
Deployment is the other gap. The README's development section ends at the backend directory, with no published start command, port or persistence layout, so an operator who needs those has to leave the README. There is also no documented rollback procedure, which matters because the release cadence is fast: 2.39.7, 2.39.8 and 2.39.9 all landed within a week in September 2026. A fast cadence with no documented rollback means you should be able to return to a previous build on your own before you upgrade.
Finally, the licence is AGPL-3.0. That is fine for personal and internal use, and it becomes a question the moment you modify Sub-Store and expose it to others over a network. The README offers no guidance on that; a lawyer should answer it, not this article.
How Sub-Store differs from a client-side subscription editor
The obvious alternative is the subscription editing built into the clients themselves. Surge, Loon, Quantumult X and mihomo all accept a remote subscription and apply some local processing, and mihomo in particular has its own proxy-provider and rule-provider machinery that can filter and override what a provider sends.
The difference is where the logic lives. In the client-side approach, each device holds its own copy of the filtering and renaming rules, so three devices mean three rule sets to keep in sync, and a change has to be repeated. Sub-Store moves that logic to one place and exposes the result as a URL, which is why the README lists collecting multiple subscriptions in one URL as a core function. The trade-off is the opposite of the client approach: you now depend on a service being reachable when a client refreshes, and a misconfigured operator chain breaks every client at once rather than one.
A second alternative is a general-purpose script that fetches a subscription and rewrites it. That works until you need the format matrix, at which point you are reimplementing the conversion layer. Sub-Store's advantage is that the matrix and the operators are maintained together; its disadvantage is that you inherit the project's release cadence and its documentation gaps along with them.
Maintenance, upgrades and licence
The repository is not archived, and the last push was on 2026-09-21. Releases are frequent: 2.39.9 on 2026-09-18, 2.39.8 and 2.39.7 both on 2026-09-15. Frequent small releases are a sign of active work, and they also mean an upgrade can arrive while you are mid-configuration. Because the README documents no rollback path, pin the build you deploy and keep the previous artifact, rather than tracking the latest release by default.
Upgrade cost is mostly configuration, not code. The two settings that can break a working setup are the CORS allowlist and, for module users, the sub.store host mapping. If you move your frontend, SUB_STORE_CORS_ALLOWED_ORIGINS or the cors module argument has to move with it, since origins are matched exactly by scheme, host and port. A frontend served over plain HTTP on a different port from the default will be blocked until you add it.
On licensing, AGPL-3.0 is a copyleft licence with a network clause. Running Sub-Store for yourself or inside an organisation is the ordinary case. Modifying it and letting other people use it over a network is where the obligations attach, and the repository's LICENSE file is the text that governs. This is a description of the licence, not legal advice; if you plan to build a service on top of Sub-Store, have counsel read the licence rather than this paragraph.
Editorial conclusion
Adopt Sub-Store if you already run several proxy clients and want one filtered, renamed subscription URL instead of editing node lists by hand; the operator pipeline and the format matrix are the reasons to bother. Skip it if you need a hosted service with an account system, or if you cannot run Node or a proxy-app module yourself, because the README points at the wiki for deployment and documents no rollback path. Before committing, verify two things on your own machine: that your client's format appears in the supported input and target lists, and that your deployment sets SUB_STORE_CORS_ALLOWED_ORIGINS (or the module's cors argument) to your actual frontend origin rather than leaving the default. The sub.store notice is the other item to read first: the domain belongs to the module rewrite rules, not to the project, and the README says requests that miss the rewrite can reach the public service.
Frequently asked questions
What is Sub-Store?
Sub-Store is a subscription manager for proxy clients. The README describes it as an advanced subscription manager for QX, Loon, Surge, Stash, Egern and Shadowrocket, and lists four core functions: conversion between formats, subscription formatting, collecting multiple subscriptions in one URL, and hosting or modifying subscriptions and files.
What does "sub store" mean in this project's name?
The name refers to a store of subscriptions: the tool keeps subscription sources and serves processed versions of them. The README does not give an etymology, but its core function list, collecting multiple subscriptions in one URL, matches that reading.
How do I install Sub-Store?
The README's development section says to install pnpm and then go to the backend directory; the repository layout shows backend/, config/ and scripts/ at the top level, with .node-version pinning Node. The README does not print a start command, port or data directory, and points to the wiki for documentation.
Which formats can Sub-Store convert between?
Inputs include proxy URI schemes, URI forms for protocols such as SS, VMess, VLESS, Trojan, Hysteria 2, TUIC v5 and WireGuard, Clash Proxies YAML, single-line Clash proxy JSON/JSON5/YAML, and the native export formats of QX, Loon, Surge and mihomo. Targets include Plain JSON, Stash, Clash.Meta (mihomo), Surfboard, Surge, SurgeMac, Loon, Egern, Shadowrocket, QX, sing-box, V2Ray and V2Ray URI.
Is there a risk in using the sub.store domain with Sub-Store?
The README states that sub.store is only the domain used by module-script rewrite MitM rules and is not owned by the project, and that a request which does not go through the rewrite will be sent to the public sub.store service. It suggests mapping sub.store to 127.0.0.1 or another local address, while noting that ordinary users may still reach the public domain after switching or toggling configuration modules.
What licence does Sub-Store use?
The repository is licensed under AGPL-3.0, and a LICENSE file sits at the top level. The README does not discuss the licence's network clause or what it means for a modified deployment.
Official sources
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.
[](https://hysenlabs.com/projects/sub-store-org-sub-store)