├── .dockerignore ├── .gitignore ├── Dockerfile ├── README.md ├── fly.toml ├── index.js ├── jsconfig.json ├── litefs.js ├── litefs └── README.md └── package.json /.dockerignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # LiteFS 4 | litefs 5 | 6 | # Logs 7 | 8 | logs 9 | _.log 10 | npm-debug.log_ 11 | yarn-debug.log* 12 | yarn-error.log* 13 | lerna-debug.log* 14 | .pnpm-debug.log* 15 | 16 | # Caches 17 | 18 | .cache 19 | 20 | # Diagnostic reports (https://nodejs.org/api/report.html) 21 | 22 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 23 | 24 | # Runtime data 25 | 26 | pids 27 | _.pid 28 | _.seed 29 | *.pid.lock 30 | 31 | # Directory for instrumented libs generated by jscoverage/JSCover 32 | 33 | lib-cov 34 | 35 | # Coverage directory used by tools like istanbul 36 | 37 | coverage 38 | *.lcov 39 | 40 | # nyc test coverage 41 | 42 | .nyc_output 43 | 44 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 45 | 46 | .grunt 47 | 48 | # Bower dependency directory (https://bower.io/) 49 | 50 | bower_components 51 | 52 | # node-waf configuration 53 | 54 | .lock-wscript 55 | 56 | # Compiled binary addons (https://nodejs.org/api/addons.html) 57 | 58 | build/Release 59 | 60 | # Dependency directories 61 | 62 | node_modules/ 63 | jspm_packages/ 64 | 65 | # Snowpack dependency directory (https://snowpack.dev/) 66 | 67 | web_modules/ 68 | 69 | # TypeScript cache 70 | 71 | *.tsbuildinfo 72 | 73 | # Optional npm cache directory 74 | 75 | .npm 76 | 77 | # Optional eslint cache 78 | 79 | .eslintcache 80 | 81 | # Optional stylelint cache 82 | 83 | .stylelintcache 84 | 85 | # Microbundle cache 86 | 87 | .rpt2_cache/ 88 | .rts2_cache_cjs/ 89 | .rts2_cache_es/ 90 | .rts2_cache_umd/ 91 | 92 | # Optional REPL history 93 | 94 | .node_repl_history 95 | 96 | # Output of 'npm pack' 97 | 98 | *.tgz 99 | 100 | # Yarn Integrity file 101 | 102 | .yarn-integrity 103 | 104 | # dotenv environment variable files 105 | 106 | .env 107 | .env.development.local 108 | .env.test.local 109 | .env.production.local 110 | .env.local 111 | 112 | # parcel-bundler cache (https://parceljs.org/) 113 | 114 | .parcel-cache 115 | 116 | # Next.js build output 117 | 118 | .next 119 | out 120 | 121 | # Nuxt.js build / generate output 122 | 123 | .nuxt 124 | dist 125 | 126 | # Gatsby files 127 | 128 | # Comment in the public line in if your project uses Gatsby and not Next.js 129 | 130 | # https://nextjs.org/blog/next-9-1#public-directory-support 131 | 132 | # public 133 | 134 | # vuepress build output 135 | 136 | .vuepress/dist 137 | 138 | # vuepress v2.x temp and cache directory 139 | 140 | .temp 141 | 142 | # Docusaurus cache and generated files 143 | 144 | .docusaurus 145 | 146 | # Serverless directories 147 | 148 | .serverless/ 149 | 150 | # FuseBox cache 151 | 152 | .fusebox/ 153 | 154 | # DynamoDB Local files 155 | 156 | .dynamodb/ 157 | 158 | # TernJS port file 159 | 160 | .tern-port 161 | 162 | # Stores VSCode versions used for testing VSCode extensions 163 | 164 | .vscode-test 165 | 166 | # yarn v2 167 | 168 | .yarn/cache 169 | .yarn/unplugged 170 | .yarn/build-state.yml 171 | .yarn/install-state.gz 172 | .pnp.* 173 | 174 | # IntelliJ based IDEs 175 | .idea 176 | 177 | # Finder (MacOS) folder config 178 | .DS_Store 179 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Bun + LiteFS 4 | bun.lockb 5 | package-lock.json 6 | litefs/db 7 | 8 | # Logs 9 | 10 | logs 11 | _.log 12 | npm-debug.log_ 13 | yarn-debug.log* 14 | yarn-error.log* 15 | lerna-debug.log* 16 | .pnpm-debug.log* 17 | 18 | # Caches 19 | 20 | .cache 21 | 22 | # Diagnostic reports (https://nodejs.org/api/report.html) 23 | 24 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 25 | 26 | # Runtime data 27 | 28 | pids 29 | _.pid 30 | _.seed 31 | *.pid.lock 32 | 33 | # Directory for instrumented libs generated by jscoverage/JSCover 34 | 35 | lib-cov 36 | 37 | # Coverage directory used by tools like istanbul 38 | 39 | coverage 40 | *.lcov 41 | 42 | # nyc test coverage 43 | 44 | .nyc_output 45 | 46 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 47 | 48 | .grunt 49 | 50 | # Bower dependency directory (https://bower.io/) 51 | 52 | bower_components 53 | 54 | # node-waf configuration 55 | 56 | .lock-wscript 57 | 58 | # Compiled binary addons (https://nodejs.org/api/addons.html) 59 | 60 | build/Release 61 | 62 | # Dependency directories 63 | 64 | node_modules/ 65 | jspm_packages/ 66 | 67 | # Snowpack dependency directory (https://snowpack.dev/) 68 | 69 | web_modules/ 70 | 71 | # TypeScript cache 72 | 73 | *.tsbuildinfo 74 | 75 | # Optional npm cache directory 76 | 77 | .npm 78 | 79 | # Optional eslint cache 80 | 81 | .eslintcache 82 | 83 | # Optional stylelint cache 84 | 85 | .stylelintcache 86 | 87 | # Microbundle cache 88 | 89 | .rpt2_cache/ 90 | .rts2_cache_cjs/ 91 | .rts2_cache_es/ 92 | .rts2_cache_umd/ 93 | 94 | # Optional REPL history 95 | 96 | .node_repl_history 97 | 98 | # Output of 'npm pack' 99 | 100 | *.tgz 101 | 102 | # Yarn Integrity file 103 | 104 | .yarn-integrity 105 | 106 | # dotenv environment variable files 107 | 108 | .env 109 | .env.development.local 110 | .env.test.local 111 | .env.production.local 112 | .env.local 113 | 114 | # parcel-bundler cache (https://parceljs.org/) 115 | 116 | .parcel-cache 117 | 118 | # Next.js build output 119 | 120 | .next 121 | out 122 | 123 | # Nuxt.js build / generate output 124 | 125 | .nuxt 126 | dist 127 | 128 | # Gatsby files 129 | 130 | # Comment in the public line in if your project uses Gatsby and not Next.js 131 | 132 | # https://nextjs.org/blog/next-9-1#public-directory-support 133 | 134 | # public 135 | 136 | # vuepress build output 137 | 138 | .vuepress/dist 139 | 140 | # vuepress v2.x temp and cache directory 141 | 142 | .temp 143 | 144 | # Docusaurus cache and generated files 145 | 146 | .docusaurus 147 | 148 | # Serverless directories 149 | 150 | .serverless/ 151 | 152 | # FuseBox cache 153 | 154 | .fusebox/ 155 | 156 | # DynamoDB Local files 157 | 158 | .dynamodb/ 159 | 160 | # TernJS port file 161 | 162 | .tern-port 163 | 164 | # Stores VSCode versions used for testing VSCode extensions 165 | 166 | .vscode-test 167 | 168 | # yarn v2 169 | 170 | .yarn/cache 171 | .yarn/unplugged 172 | .yarn/build-state.yml 173 | .yarn/install-state.gz 174 | .pnp.* 175 | 176 | # IntelliJ based IDEs 177 | .idea 178 | 179 | # Finder (MacOS) folder config 180 | .DS_Store 181 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax = docker/dockerfile:1 2 | 3 | # Adjust BUN_VERSION as desired 4 | ARG BUN_VERSION=1.0.26 5 | FROM oven/bun:${BUN_VERSION}-slim as base 6 | 7 | LABEL fly_launch_runtime="Bun" 8 | 9 | # Bun app lives here 10 | WORKDIR /app 11 | 12 | # Set production environment 13 | ENV NODE_ENV="production" 14 | 15 | 16 | # Throw-away build stage to reduce size of final image 17 | FROM base as build 18 | 19 | # Install packages needed to build node modules 20 | RUN apt-get update -qq && \ 21 | apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3 22 | 23 | # Install node modules 24 | COPY --link bun.lockb package.json ./ 25 | RUN bun install --ci 26 | 27 | # Copy application code 28 | COPY --link . . 29 | 30 | 31 | # Final stage for app image 32 | FROM base 33 | 34 | # Copy built application 35 | COPY --from=build /app /app 36 | 37 | # Start the server by default, this can be overwritten at runtime 38 | EXPOSE 3000 39 | CMD [ "bun", "index.js" ] 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fly.io -> Bun + SQLite 2 | 3 | **Social Media Photo by [Annie Ruygt](https://annieruygtillustration.com/) on [fly.io](https://fly.io/blog/flydotio-heart-bun/)** 4 | 5 | This project uses [Bun](https://bun.sh), a fast all-in-one JavaScript runtime. 6 | 7 | To install dependencies: 8 | 9 | ```bash 10 | bun install 11 | ``` 12 | 13 | To run: 14 | 15 | ```bash 16 | bun index.js 17 | ``` 18 | 19 | ## Deploy with fly 20 | 21 | ```sh 22 | # login via GitHub or Google or .. whatever 23 | fly auth login 24 | 25 | # be sure the region is correct and/or free to use 26 | # be sure you use 1x CPU with 256MB machine for free tier 27 | fly launch 28 | 29 | # for free tier use just 1 volume 30 | fly volume create litefs -r $REGION -n 1 31 | 32 | # deploy this and have fun 33 | fly deploy 34 | ``` 35 | 36 | **[Live Demo](https://fly-bun-sqlite.fly.dev/)** 37 | -------------------------------------------------------------------------------- /fly.toml: -------------------------------------------------------------------------------- 1 | # fly.toml app configuration file generated for fly-bun-sqlite on 2024-02-14T14:39:33+01:00 2 | # 3 | # See https://fly.io/docs/reference/configuration/ for information about how to use this file. 4 | # 5 | 6 | app = 'fly-bun-sqlite' 7 | primary_region = 'ams' 8 | 9 | [build] 10 | 11 | [[mounts]] 12 | source = 'litefs' 13 | destination = '/var/lib/litefs' 14 | 15 | [http_service] 16 | internal_port = 3000 17 | force_https = true 18 | auto_stop_machines = true 19 | auto_start_machines = true 20 | min_machines_running = 0 21 | processes = ['app'] 22 | 23 | [[vm]] 24 | size = 'shared-cpu-1x' 25 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import {serve} from 'bun'; 2 | 3 | // grab the db or some utility 4 | import {all} from './litefs.js'; 5 | 6 | // grab the port and start the server 7 | const port = process.env.PORT || 3000; 8 | 9 | serve({ 10 | fetch(request) { 11 | const greeting = "

Hello From Bun on Fly!

"; 12 | const results = `
${JSON.stringify(
13 |       all`SELECT * FROM persons ORDER BY id DESC`, null, '\t')
14 |     }
`; 15 | return new Response(greeting + '
' + results, { 16 | headers: {'Content-Type': 'text/html; charset=utf-8'} 17 | }); 18 | }, 19 | error(error) { 20 | return new Response("Uh oh!!\n" + error.toString(), { status: 500 }); 21 | }, 22 | port 23 | }); 24 | 25 | console.log(`Flying Bun app listening on http://0.0.0.0:${port}/`); 26 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["ESNext"], 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | "moduleDetection": "force", 7 | "jsx": "react-jsx", 8 | "allowJs": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "verbatimModuleSyntax": true, 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "skipLibCheck": true, 18 | "strict": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "forceConsistentCasingInFileNames": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /litefs.js: -------------------------------------------------------------------------------- 1 | import {existsSync} from 'fs'; 2 | import {join} from 'path'; 3 | import {Database} from 'bun:sqlite'; 4 | import createSQLiteTags from 'better-tags'; 5 | 6 | // use mounted point on production, use local folder otherwise 7 | const litefs = join( 8 | process.env.NODE_ENV === 'production' ? '/var/lib' : '.', 9 | 'litefs' 10 | ); 11 | 12 | // if litefs folder doesn't exist get out! 13 | if (!existsSync(litefs)) { 14 | console.error('Unable to reach', litefs); 15 | process.exit(1); 16 | } 17 | 18 | // shared db + template literals based utilities 19 | const {db, get, all, values, exec, run, entries, transaction} = 20 | createSQLiteTags(new Database(join(litefs, 'db'))); 21 | 22 | export {db, get, all, values, exec, run, entries, transaction}; 23 | 24 | /////////////////////////////////////////////////////////////// 25 | // FOR DEMO SAKE ONLY - EXECUTED ON EACH DEPLOY / REVIVAL 26 | /////////////////////////////////////////////////////////////// 27 | 28 | // some table schema 29 | exec` 30 | CREATE TABLE IF NOT EXISTS persons ( 31 | id INTEGER PRIMARY KEY AUTOINCREMENT, 32 | name TEXT NOT NULL, 33 | phone TEXT NOT NULL, 34 | company TEXT NOT NULL 35 | ) 36 | `; 37 | 38 | // some table entry 39 | exec` 40 | INSERT INTO persons 41 | (name, phone, company) 42 | VALUES 43 | (${ 44 | crypto.randomUUID() 45 | }, ${ 46 | ('+' + (Date.now() * Math.random())).replace(/[^+\d]/, ' ') 47 | }, 'fly.io') 48 | `; 49 | -------------------------------------------------------------------------------- /litefs/README.md: -------------------------------------------------------------------------------- 1 | # litefs 2 | 3 | This folder can contain one or more SQLite databases. 4 | 5 | Its name is reflected in production after mounting it. 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fly-bun-sqlite", 3 | "module": "index.js", 4 | "type": "module", 5 | "scripts": { 6 | "start": "bun index.js", 7 | "update:bun": "sed -i \"s/ARG BUN_VERSION=.*/ARG BUN_VERSION=$(bun --version)/\" Dockerfile" 8 | }, 9 | "devDependencies": { 10 | "@flydotio/dockerfile": "latest", 11 | "@types/bun": "latest" 12 | }, 13 | "peerDependencies": { 14 | "typescript": "latest" 15 | }, 16 | "dependencies": { 17 | "better-tags": "latest" 18 | } 19 | } 20 | --------------------------------------------------------------------------------