Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
4724e86
Remove Google Analytics tracking
neuhaus Apr 30, 2026
99f3a94
Switch url and sql parameters from query string to hash fragment and …
neuhaus Apr 30, 2026
7cbbd79
Add usage examples for url and sql hash parameters in README
neuhaus Apr 30, 2026
bfe010a
Update hash sql parameter on query execution and skip default select …
neuhaus Apr 30, 2026
6d2f506
Add dark mode support with system theme detection
neuhaus Apr 30, 2026
c053f06
Support relative URLs and improve dark mode string colors
neuhaus Apr 30, 2026
2f4d24d
Revert unnecessary relative URL fix; XMLHttpRequest resolves relative…
neuhaus Apr 30, 2026
a7be097
Simplify license notice in README
neuhaus Apr 30, 2026
8841b16
Fix dark mode: use pure black background and style Select2 dropdown
neuhaus May 1, 2026
e230fab
improve README
neuhaus May 23, 2026
b577f8f
Fix XSS vulnerability in table name rendering
neuhaus May 23, 2026
028db1c
Use relative path for sql-wasm.wasm
neuhaus May 23, 2026
08c1906
Remove unused Select2 image assets
neuhaus May 23, 2026
b9919c1
Remove source map files from repository
neuhaus May 23, 2026
453d089
Remove dead #success-box reference
neuhaus May 23, 2026
16cc7e5
Remove obsolete social-media preload tags
neuhaus May 23, 2026
9b88ace
Use proper SQL identifier quoting for table names
neuhaus May 23, 2026
a5ffe95
Remove mindmup-editabletable.js plugin
neuhaus May 23, 2026
3d740ed
Replace XMLHttpRequest with fetch API
neuhaus May 23, 2026
955d4f8
Use strict equality operators consistently
neuhaus May 23, 2026
b7be8fd
Expand .gitignore
neuhaus May 23, 2026
3576dbd
Update copyright year to 2026
neuhaus May 23, 2026
b53e368
Revert "Update copyright year to 2026"
neuhaus May 23, 2026
fa39493
Upgrade jQuery to 4.0.0 slim
neuhaus May 23, 2026
c12a691
Modernize filereader.js to avoid deprecated arguments.callee
neuhaus May 23, 2026
aab8a26
Clean up index.html event handlers by removing unused parameters
neuhaus May 23, 2026
c8d4313
Improve wording of empty query result message
neuhaus May 23, 2026
4b42b82
Modernize and correct browser compatibility error message
neuhaus May 23, 2026
e460738
Upgrade sql.js to version 1.14.1
neuhaus May 23, 2026
eeafdf4
Replace filereader.js with native HTML5 drag-and-drop and file input …
neuhaus May 23, 2026
0cdd13f
Replace Ace Editor with ultra-lightweight CodeJar and Prism.js
neuhaus May 23, 2026
3b4348b
upgrade to bootstrip 5.3.8
neuhaus May 23, 2026
67f80f5
Migrate SQLite parsing and querying to background Web Worker thread
neuhaus May 23, 2026
f04b5ea
Remove obsolete sql-wasm.js script after migrating to Web Worker
neuhaus May 23, 2026
2d3a1a6
Support loading SQLite databases directly from uploaded ZIP archives
neuhaus May 23, 2026
c1544b6
zipped sample file
neuhaus May 23, 2026
627f709
Fix jQuery 4.0 Select2 compatibility, CodeJar syntax error, and moder…
neuhaus May 23, 2026
949e035
Support relative and zipped URL database loading cleanly via handleZi…
neuhaus May 23, 2026
0703c6c
better README
neuhaus May 23, 2026
41b3c78
README
neuhaus May 23, 2026
5f45f47
Modernize database engine: Transition from legacy sql.js to official …
neuhaus May 23, 2026
afa5795
Fix worker error: bypass deleted sqlite3.util namespace with local is…
neuhaus May 23, 2026
a6aed09
list libraries
neuhaus May 23, 2026
e46cac8
update preview image
neuhaus May 23, 2026
58a7676
README *
neuhaus May 23, 2026
1ff3770
Link to live example
neuhaus May 23, 2026
58a1703
Fix dropdown sync: automatically refresh table select box on schema/d…
neuhaus May 23, 2026
e39fff4
Fix: Reset lastCachedQueryCount cache when rows are inserted or delet…
neuhaus May 23, 2026
e163eeb
Add Docker containerization support: Lightweight Alpine Nginx with en…
neuhaus May 23, 2026
9dbb8b5
Document Docker containerization in README.md
neuhaus May 23, 2026
00b02b2
Fix: Update Chinook_Sqlite file reference from .sqlite to .zip and ad…
neuhaus May 23, 2026
6675005
UX: Dynamically sync address bar url hash parameter on remote and loc…
neuhaus May 23, 2026
d258b1e
Fix: Defer updateHashUrl until after successful database load inside …
neuhaus May 23, 2026
1aec955
Fix: Correct single-quote escaping in entrypoint.sh to generate valid…
neuhaus May 23, 2026
3b4b97f
Build: Add .dockerignore to exclude examples, reference assets, and g…
neuhaus May 23, 2026
49ce890
update .dockerignore
neuhaus May 23, 2026
5cd712a
update ignore file
neuhaus May 23, 2026
b5b16f5
Security: Prevent leakage of Dockerfiles and Git configurations in th…
neuhaus May 23, 2026
895e174
Refactor: Move Docker configurations to a dedicated docker/ subdirect…
neuhaus May 23, 2026
4d6daaa
Fix pagination bug: wrap complex SELECT queries in an outer COUNT wra…
neuhaus May 23, 2026
b21ca2c
Refine SQL LIMIT regex and parsing to support all standard syntaxes a…
neuhaus May 23, 2026
d3b922f
Add partitioned query history with localStorage persistence
neuhaus May 23, 2026
fe116a7
Fix Copy button in query history for Firefox
neuhaus May 23, 2026
c0ee8ed
Fix Copy button: use synchronous textarea approach
neuhaus May 23, 2026
dd4813d
Fix Copy: append textarea inside offcanvas to bypass focus trap
neuhaus May 23, 2026
9c527fe
Stack Execute and History buttons vertically next to SQL editor
neuhaus May 23, 2026
d25e393
README update
neuhaus May 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Exclude Git files
.git
.gitignore

# Exclude sample databases
examples

# Exclude development files and documentation
README.md
LICENSE
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
.idea/*
.idea/
.DS_Store
*.swp
*.swo
*~
node_modules/
*.map
/sqlite-wasm-3530100/
84 changes: 61 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,62 @@
[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-SQLite%20Viewer-brightgreen.svg?style=flat)](http://android-arsenal.com/details/1/2497)

SQLite Viewer
============

*View SQLite file online. Uses [sql.js](https://github.com/sql-js/sql.js) for parsing sqlite files.*

You can also load remote files (using JS ajax, remote server must send `Access-Control-Allow-Origin:*`):
`http://inloop.github.io/sqlite-viewer/?url=http://example.com/data.sqlite`

![](/img/preview.png?raw=true "Example sqlite")

### License
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=============

*View SQLite file online directly in your browser.*

The database will be loaded into your memory and changes will not affect the file you loaded it from. You can
however export the database after making changes.

You can also load remote files (using JS ajax, remote server must send `Access-Control-Allow-Origin:*`)
and prefill a SQL query using hash parameters:

- To load a remote SQLite file upon page load, append<br>
`#url=examples/Chinook_Sqlite.zip` to the URL. Both absolute and relative URLs work. So do zipped files.
- To prefill a SQL query, append<br>
`#sql=SELECT%20*%20FROM%20table` to the URL.
- To load a remote file *and* prefill a query at the same time: Append both like this:<br>
`#url=examples/Chinook_Sqlite.zip&sql=SELECT%20*%20FROM%20table`

![](/img/preview.png?raw=true "Screenshot")

Try [this live example](https://neuhaus.github.io/sqlite-viewer/#url=examples%2FChinook_Sqlite.zip&sql=SELECT+%0A++++Album.AlbumId%2C%0A++++Album.Title+AS+AlbumTitle%2C%0A++++Track.TrackId%2C%0A++++Track.Name+AS+TrackName%0AFROM+Album%0AJOIN+Track+ON+Album.AlbumId+%3D+Track.AlbumId%0AORDER+BY+Album.AlbumId%2C+TrackId%0ALIMIT+0%2C40%3B+)!

## Docker

You can run and configure the SQLite Viewer inside a lightweight production container using Docker.

### 1. Build the Docker Image
Execute the following build command in your workspace directory:
```bash
docker build -t sqlite-viewer -f docker/Dockerfile .
```

### 2. Auto-load a Database via Volume Mount
To mount your local database file or ZIP archive and have the application **automatically fetch and load it** on page load:
```bash
docker run --rm -p 8080:80 \
-v "${PWD}/examples/Chinook_Sqlite.zip:/var/www/data.zip" \
sqlite-viewer
```
*Note: Navigate to `http://localhost:8080` in your browser. The database tables will load instantly with zero user interaction.*

### 3. Configure Default SQL Query & Database URL
You can specify a custom database URL and auto-execute a default SQL query on startup using environment variables:
```bash
docker run --rm -p 8080:80 \
-e DEFAULT_URL="examples/Chinook_Sqlite.zip" \
-e DEFAULT_SQL="SELECT name, type FROM sqlite_master WHERE type='table' ORDER BY name;" \
sqlite-viewer
```
* **`DEFAULT_URL`**: The database at this URL/path (relative path or absolute URL) will be fetched and opened on page load. Both raw databases and `.zip` archives are supported.
* **`DEFAULT_SQL`**: The code editor will be pre-populated and this query will execute automatically on startup.

## Libraries

- Using the official [sqlite3-wasm](https://sqlite.org/wasm/doc/trunk/index.md) for parsing sqlite files.
- Can handle SQLite files in ZIP files, thanks to [jszip](https://stuk.github.io/jszip/).
- Enjoy query editing with SQL syntax highlighting thanks to [CodeJar](https://medv.io/codejar/) and [PrismJS](https://prismjs.com/).
- Using [jQuery](https://jquery.com/) 4.0 slim, [Bootstrap](https://getbootstrap.com/) 5.3.8, [select2](https://select2.org/) and [FileSaver.js](https://github.com/eligrey/FileSaver.js/).

## License

Licensed under the Apache License, Version 2.0 — see [LICENSE](LICENSE) for details.
6 changes: 3 additions & 3 deletions css/bootstrap.min.css

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion css/bootstrap.min.css.map

This file was deleted.

123 changes: 110 additions & 13 deletions css/main.css
Original file line number Diff line number Diff line change
@@ -1,31 +1,94 @@
body {
background: #f5f5f5;
}
@media (prefers-color-scheme: light) {
body {
background: #f5f5f5;
}

.drag {
background-color: lightblue;
}

#header {
background: #A0CFFF;
color: #3474A8;
}

.table-hover tbody tr:hover td, .table-hover tbody tr:hover th {
background-color: #F5F5E7;
}

.drag {
background-color: lightblue;
/* Prism Light Mode Token Colors */
.token.keyword { color: #0033cc; font-weight: bold; }
.token.string { color: #036a3e; }
.token.number { color: #a626a4; }
.token.punctuation { color: #383a42; }
.token.operator { color: #0184a6; }
.token.comment { color: #a0a1a7; }
}

#header {
background: #A0CFFF;
color: #3474A8;
@media (prefers-color-scheme: dark) {
body {
background: #000;
}

.drag {
background-color: #1e3a5f;
}

#header {
background: #0d3b66;
color: #7ab5e6;
}

.table-hover tbody tr:hover td, .table-hover tbody tr:hover th {
background-color: #2c2c1e;
}

/* Prism Dark Mode Token Colors */
.token.keyword { color: #c5a3ff !important; font-weight: bold; }
.token.string { color: #a8df8e !important; }
.token.number { color: #7ec8e3 !important; }
.token.punctuation { color: #ccc; }
.token.operator { color: #ff7b72; }
.token.comment { color: #8b949e; }

.select2-container--bootstrap-5 .select2-selection {
background-color: #212529 !important;
border-color: #495057 !important;
color: #fff !important;
}

.select2-container--bootstrap-5 .select2-dropdown {
background-color: #212529 !important;
border-color: #495057 !important;
}

.select2-container--bootstrap-5 .select2-results__option--highlighted[aria-selected] {
background-color: #0d6efd !important;
}

.select2-container--bootstrap-5 .select2-search__field {
background-color: #212529 !important;
color: #fff !important;
}
}

#dropzone {
height: 450px;
cursor: pointer;
transition: height 0.5s ease;
}

#output-box {
display: none;
}

.ace_hidden-cursors {
opacity: 0;
transition: opacity 0.5s ease;
}

.table-hover tbody tr:hover td, .table-hover tbody tr:hover th {
background-color: #F5F5E7;
#sql-editor {
height: 120px;
font-family: var(--bs-font-monospace), monospace;
font-size: 16px;
overflow-y: auto;
}

#data {
Expand All @@ -42,3 +105,37 @@ body {
text-overflow: ellipsis;
white-space: nowrap;
}

/* Query History Sidebar Custom Styling */
.query-card {
border-radius: 6px;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.query-card:hover {
transform: translateY(-1px);
}

.query-card pre {
max-height: 90px;
font-family: var(--bs-font-monospace), monospace;
font-size: 13px;
border-radius: 4px;
border: 1px solid var(--bs-border-color);
background-color: var(--bs-tertiary-bg) !important;
color: var(--bs-body-color) !important;
cursor: pointer;
transition: filter 0.15s ease, background-color 0.15s ease;
}

.query-card pre:hover {
filter: brightness(0.95);
background-color: var(--bs-secondary-bg) !important;
}

/* Make sure dark mode handles brightness correctly */
@media (prefers-color-scheme: dark) {
.query-card pre:hover {
filter: brightness(1.15);
}
}
25 changes: 25 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM nginx:alpine

# 1. Copy all static viewer assets to the default Nginx root
COPY . /usr/share/nginx/html

# Remove Docker subdirectory and Git configurations from the public web root for security
RUN rm -rf /usr/share/nginx/html/docker \
/usr/share/nginx/html/.dockerignore \
/usr/share/nginx/html/.gitignore

# 2. Copy the customized Nginx configuration
COPY docker/nginx.conf /etc/nginx/nginx.conf

# 3. Setup the entrypoint script
COPY docker/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# 4. Create directory for volume mounts
RUN mkdir -p /var/www

# Expose standard HTTP port
EXPOSE 80

# Run entrypoint script on boot
ENTRYPOINT ["/entrypoint.sh"]
41 changes: 41 additions & 0 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/sh
set -e

echo "=== SQLite Viewer Container Booting ==="

# 1. Check if database volume is mounted at the standard locations
if [ -f "/var/www/data.zip" ]; then
echo "-> Detected mounted SQLite database ZIP at /var/www/data.zip"
if [ -z "$DEFAULT_URL" ]; then
# Default URL to the mapped Nginx route
DEFAULT_URL="data.zip"
echo "-> Automatically setting DEFAULT_URL to: data.zip"
fi
elif [ -f "/var/www/data.sqlite" ]; then
echo "-> Detected mounted SQLite database at /var/www/data.sqlite"
if [ -z "$DEFAULT_URL" ]; then
# Default URL to the mapped Nginx route
DEFAULT_URL="data.sqlite"
echo "-> Automatically setting DEFAULT_URL to: data.sqlite"
fi
fi

# 2. Escape backslashes and single quotes in SQL to prevent breaking JS syntax
ESCAPED_SQL=$(echo "$DEFAULT_SQL" | sed 's/\\/\\\\/g' | sed "s/'/\\\\\\'/g")

echo "-> Generating client-side configuration..."
echo " DEFAULT_URL: ${DEFAULT_URL:-none}"
echo " DEFAULT_SQL: ${DEFAULT_SQL:-none}"

# 3. Write dynamic config to the webserver directory
cat << EOF > /usr/share/nginx/html/js/config.js
// Client-side application configuration
// Generated dynamically at container boot.
window.APP_CONFIG = {
defaultUrl: "${DEFAULT_URL}",
defaultSql: '${ESCAPED_SQL}'
};
EOF

echo "=== Starting Nginx Web Server ==="
exec nginx -g 'daemon off;'
44 changes: 44 additions & 0 deletions docker/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

server {
listen 80;
server_name localhost;

location / {
root /usr/share/nginx/html;
index index.html index.htm;

# WASM compatibility and cross-origin isolation headers
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
}

# Expose the mounted SQLite database file under the same origin
location /data.sqlite {
alias /var/www/data.sqlite;

# Enable basic headers and COOP/COEP
add_header Access-Control-Allow-Origin "*" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
default_type application/x-sqlite3;
}

# Expose the mounted SQLite database ZIP archive under the same origin
location /data.zip {
alias /var/www/data.zip;

# Enable basic headers and COOP/COEP
add_header Access-Control-Allow-Origin "*" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
default_type application/zip;
}
}
}
Binary file removed examples/Chinook_Sqlite.sqlite
Binary file not shown.
Binary file added examples/Chinook_Sqlite.zip
Binary file not shown.
Binary file modified img/preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed img/select2-spinner.gif
Binary file not shown.
Binary file removed img/select2.png
Binary file not shown.
Binary file removed img/select2x2.png
Binary file not shown.
Loading