Open-source project
DeadWaveWave/demo2apk avatar
DeadWaveWave/demo2apk

Demo2APK: packaging HTML and React projects into Android APKs without an Android toolchain

Turn your Vibe Coding ideas into runnable Android Apps instantly

630 stars66 forksTypeScriptLicense varies

At a glance

What is it?
Demo2APK is a self-hostable web service that wraps uploaded HTML, JSX or React/Vite projects into installable APKs through a queue-backed build worker. It removes the Android SDK from the loop, but the React path has a documented blank-screen failure mode you have to handle yourself.
Who is it for?
Adopt Demo2APK if you produce browser-based demos and need a downloadable APK without installing Android Studio, and you are willing to run the Docker deployment or accept the public instance's 5 builds per IP per hour. Do not adopt it if you need signed release builds, Play Store submission artifacts, or long-lived hosting of the APK: artifacts are deleted after 2 hours by design.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 180 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 September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What Demo2APK removes from the Android build loop

The project targets a narrow but real gap. Vibe Coding tools (the README names Gemini, ChatGPT and DeepSeek) produce single HTML files, JSX snippets, or React/Vite folders. Turning any of those into something you can install on a phone normally means installing the Android SDK, Gradle, and a WebView wrapper, then wiring the assets in. Demo2APK's pitch is that you upload files and get an APK back. The audience is people who can write a prompt but have no Android toolchain, plus teams that want a repeatable internal service for turning prototypes into installable artifacts.

The README is explicit about what it is not: it warns users not to accept APK files from others because they may carry security risks. That warning is worth reading as a statement about trust boundaries. The service packages code you supply into an installable binary, so the binary inherits whatever the supplied code does.

How the build pipeline is wired: API server, Redis queue, worker

The repository is a pnpm workspace with a packages/ directory, and the root package.json exposes the process split directly. pnpm dev runs the backend API, pnpm worker runs the build worker, and pnpm frontend runs the web UI. Redis is a required dependency: the local development instructions start redis:alpine on port 6379, and .env.example sets REDIS_URL=redis://localhost:6379. So the architecture is an API server that accepts uploads, a Redis-backed queue, and one or more workers that perform the actual packaging.

Concurrency is controlled by WORKER_CONCURRENCY, documented as defaulting to 2, and the README describes a queue system with progress feedback for excess builds. Storage paths are configurable through BUILDS_DIR, UPLOADS_DIR and LOGS_DIR. The README states that file types are detected automatically (HTML, React, ZIP) and that the tool picks a build strategy accordingly, with three input modes: single file (.html, .js, .jsx, .ts, .tsx with React component detection), pasted code, and ZIP archives covering both standard React/Vite projects and multi-file HTML projects that need no build step.

Two cleanup behaviours matter operationally. FILE_RETENTION_HOURS defaults to 2, and a background worker scans for expired files every 30 minutes by default (FILE_CLEANUP_INTERVAL_MINUTES=30). CLEANUP_UPLOADS_ON_COMPLETE defaults to true, and CLEANUP_BUILD_ARTIFACTS controls whether Cordova/Capacitor working directories are deleted after each build. The README also claims a Smart Offline step that handles CDN resources and JSX compilation so the app runs without a network, though the README does not describe the mechanism beyond that.

Installing Demo2APK with Docker and running a first build

The README gives Docker as the primary path for Linux servers and states the pre-built images only support linux/amd64. The four commands below create a deployment directory, fetch the compose file, fetch the example environment file, and start the services. After the last command, the README says to visit http://127.0.0.1:5173 for the web UI.

bash
mkdir -p ~/demo2apk && cd ~/demo2apk
curl -O https://raw.githubusercontent.com/DeadWaveWave/demo2apk/main/docker-compose.deploy.yml
curl -O https://raw.githubusercontent.com/DeadWaveWave/demo2apk/main/.env.deploy.example
mv .env.deploy.example .env
docker compose -f docker-compose.deploy.yml up -d

For macOS or local development, the README prescribes pnpm plus a Redis container, then three separate terminal processes. The build step compiles the workspace before any service starts.

bash
pnpm install
docker run -d -p 6379:6379 redis:alpine
pnpm build
pnpm dev        # API Server (port 3000)
pnpm worker     # Build Worker
pnpm frontend   # Web UI (port 5173)

If you prefer a script over the UI, the REST API accepts multipart uploads. This example posts a single HTML file and names the resulting app; the README shows the same shape for /api/build/zip and /api/build/code.

bash
curl -X POST http://localhost:3000/api/build/html \
  -F "file=@test-demo.html" \
  -F "appName=TestDemo"

The README does not document the response body of these endpoints in the excerpt available here; it points to docs/API.md for the full reference. What you should expect from the UI is a queued job with progress feedback and, on completion, a shareable download link.

The React blank screen is the failure mode to plan for

The most concrete limitation in the README is not a missing feature, it is a compatibility trap. React/Vite APKs can render a white or blank screen because older Android WebViews do not support the JavaScript features a default Vite build emits. The README's fix is to add @vitejs/plugin-legacy and terser as dev dependencies and configure the legacy plugin with targets of chrome >= 52 and android >= 5, plus base: './'.

javascript
// vite.config.js
import legacy from '@vitejs/plugin-legacy'

export default defineConfig({
  plugins: [
    react(),
    legacy({ targets: ['chrome >= 52', 'android >= 5'] })
  ],
  base: './'  // Required for APK!
})

The base: './' line is marked as required, which tells you the packaged assets are loaded from a relative path inside the APK rather than from a web root. If you skip it, the build may succeed and the app may still fail to load its own bundle. The README links a longer troubleshooting document at docs/REACT_PROJECT_REQUIREMENTS.md, which is where you would go when the screen stays white. This is the kind of problem that does not appear until you install the APK on a real device, so budget a test pass on the oldest Android version you intend to support.

Retention, rate limits and the self-hosting trade-off

Demo2APK is not a hosting service, and the defaults make that clear. Generated APKs and temporary files are deleted after 2 hours, and uploaded inputs are deleted on completion by default. If you want a permanent download URL, you need to copy the artifact out before the cleanup worker runs. The public instance at demo2apk.lasuo.ai allows 5 builds per IP per hour with no registration; self-hosting lifts that ceiling but hands you the storage and cleanup problem.

Rate limiting is configurable. RATE_LIMIT_ENABLED=false disables it for development and testing, and RATE_LIMIT_MAX changes the default of 5. There is also an optional PWA path: setting PWA_ENABLED=false by default, the worker can export a PWA site when a build request includes publishPwa=true, writing each site into PWA_DIR. PWA_HOST_SUFFIX, if set, makes the status API return a full URL under that suffix. PWA_RETENTION_HOURS falls back to FILE_RETENTION_HOURS when unset.

A different alternative is Capacitor, which the repository's cleanup settings reference by name. Capacitor is a framework you install into your own project: you run npx cap add android, keep the Android project in your repository, and build with Gradle on a machine that has the Android SDK. Demo2APK inverts that: the Android project is generated by the worker and never becomes part of your codebase. The trade-off is control. With Capacitor you can edit the native project, add plugins, and produce a signed release build. With Demo2APK you get an installable artifact from a web UI or a curl call, and you accept the defaults the worker chooses.

Maintenance status, licence and update cost

The last push to the default branch was on 2026-03-20, roughly six months before this writing, and the repository is not archived. There are no releases retrieved for this project, so version 2.3.0 in package.json and the README badge is the only version signal available. The changelog is referenced as CHANGELOG.md but its contents are not documented in the README, so there is no way to judge how frequently behaviour changes between versions.

Upgrading a Docker deployment is one documented command pair, which keeps the operational cost low: pull the new image and bring the stack up again. The repository ships both docker-compose.deploy.yml and docker-compose.dev.yml, plus .env.deploy.example and .env.example, so environment drift between deploy and development is at least visible in the file layout. The root package.json pins pnpm@9.12.0 and requires Node >=20.0.0, so a self-hosted worker running an older Node LTS will not match the stated engines field.

On licensing: the README carries an MIT badge, but the repository metadata does not state a licence, and no LICENSE file appears in the top-level entries. The badge is a claim, not the licence text. Before you redistribute the images or ship builds to customers, confirm the actual licence file in the repository. That is a factual gap to close, not a legal question this article can settle.

Editorial conclusion

Adopt Demo2APK if you produce browser-based demos and need a downloadable APK without installing Android Studio, and you are willing to run the Docker deployment or accept the public instance's 5 builds per IP per hour. Do not adopt it if you need signed release builds, Play Store submission artifacts, or long-lived hosting of the APK: artifacts are deleted after 2 hours by design. Before committing, verify the licence situation (the README badge says MIT but the repository's licence field is unknown), and build one React/Vite project with the legacy plugin and base: './' to confirm the WebView path works for your target Android versions.

Frequently asked questions

What is Demo2APK and what kinds of files can I upload?

Demo2APK is a one-click packaging tool that turns Vibe Coding output into installable Android APKs. It accepts single files (.html, .js, .jsx, .ts, .tsx with React detection), pasted code, and ZIP archives containing either a standard React/Vite project or a multi-file HTML project.

How do I install and self-host Demo2APK?

The README gives a Docker deployment for Linux servers using docker-compose.deploy.yml, with the web UI on port 5173. The pre-built Docker images only support linux/amd64; macOS users are pointed to the local development path with pnpm, Redis on port 6379, and separate dev, worker and frontend processes.

Why does my React app show a blank screen in the Demo2APK APK?

The README attributes this to Android WebView compatibility. It instructs you to install @vitejs/plugin-legacy and terser, configure the legacy plugin with targets chrome >= 52 and android >= 5, and set base: './' in vite.config.js, which the README marks as required for APK builds.

How long are Demo2APK build artifacts kept?

Generated APKs and temporary files are deleted after 2 hours by default, controlled by FILE_RETENTION_HOURS. A background worker scans for expired files every 30 minutes, and uploaded inputs are deleted after each job unless CLEANUP_UPLOADS_ON_COMPLETE is changed.

Is there a rate limit on Demo2APK builds?

Yes. The public instance allows 5 builds per IP per hour with no registration, and self-hosted instances apply the same default through RATE_LIMIT_MAX. Rate limiting can be turned off for development with RATE_LIMIT_ENABLED=false.

Official sources

  1. DeadWaveWave/demo2apk on GitHub
  2. Issues
  3. README
Community notes

Community notes