Most data projects do not need a server at all. A static site on a free platform hosts a story, a chart or a searchable dataset for nothing, and a small cloud instance costs a few dollars a month when you do need real processing. This guide walks through how to host a data project cheaply, path by path.
One clarification before anything else, because search engines keep getting this one wrong. Here a data project means a dataset-driven web page: a mapped story, an interactive chart, a searchable database of records. It does not mean a physical data center. If that is what you are building, you are in a different category entirely.
The teams who struggle with this usually know how to build the project and then get stuck on the last mile: where the 40 MB GeoJSON file lives, whether the free tier needs a credit card, and what happens to the bill when a story gets traffic. Those are the questions below, and they are the ones I would have wanted answered the first time I put a data story online.
What You Need Before You Host a Data Project Cheaply
You need two things: a built project that produces plain files, and a place to serve them. Everything else is optional.
There are two practical deployment paths, and picking the wrong one is the most expensive mistake a small team can make.
- Static hosting suits anything the browser can do on its own: charts drawn client-side, pages built from templates, embedded Flourish or Datawrapper visuals, documentation sites, Observable notebooks exported to HTML. You push files, the platform serves them from a CDN. No server process, no idle bill, nothing to patch at 2am.
- A small cloud server suits projects that need scheduled jobs, private data, per-request filtering over a large dataset, or a language runtime that must stay warm. It costs money every month whether anyone visits or not.
A middle path exists: static hosting for the pages plus a serverless function for the few requests that genuinely need compute. Most teams can stay on that middle path indefinitely.
Prerequisites checklist
- A Git repository holding your project. Any host in this guide deploys from Git.
- A build output: a folder of HTML, CSS, JavaScript and data files. If you use Jekyll, Hugo, Astro or Quarto, the generator produces this folder for you.
- Your data in open formats: CSV, GeoJSON, JSON, Parquet. Closed formats tie your site to one vendor’s tool.
- A Git provider account. Free tiers exist at GitHub, GitLab and others, and a private repository generally deploys fine.
- A domain name, roughly 10 to 15 dollars a year, only if you want a clean URL.
- A runtime and a process manager, plus SSH access, for the server path only.
- The security basics: no credentials committed to the repository, secrets in environment variables, and an account with two-factor authentication.
What each path costs
| Path | Typical monthly cost | Maintenance effort | Best for |
|---|---|---|---|
| Free static platform | 0 dollars | Occasional rebuilds when data changes | Charts, stories, docs, notebooks |
| Static platform on a paid plan | Under 25 dollars | Same as free, plus more build minutes | Projects with heavy builds or big datasets |
| Static plus serverless functions | 0 to a few dollars | Occasional cold-start complaints | Light API work, form handling |
| Small Linux VM | About 4 to 8 dollars | Monthly updates, backups, monitoring | Scheduled jobs, private data, large files |
| Managed database | Often 15 to 30 dollars before use | Backups and query tuning | Records that change often and need auth |
Step-by-Step: From a Local Project to a Live URL
Here is the full workflow for both paths, including a verification checklist at the end.
How to Choose the Right Hosting Approach
Start static unless something forces you off it. If the site reads a CSV or JSON file with fetch and renders it in the browser, it is a static project, and static hosting is the right answer. If it needs a recurring fetch from a source that requires a secret key, a scheduled refresh, or row-level access control, you need compute.
Ask three questions in order. Does the data change while readers are on the page? Does anything have to stay private? Does your dataset exceed what a browser should download at once? Two yes answers on the same question and you want a small server. Zero yes answers across all three and stay static.
Press coverage is the underrated fourth question. Traffic spikes from a front-page link can exhaust a free bandwidth allowance or, worse, trigger a usage charge. If a launch is planned, decide which host you would move to before it happens, not after.
Optimize the Project Before Deployment
Most hosting problems are file-size problems wearing a costume. Cut the payload before you pick a platform.
Preprocess the data at build time instead of shipping raw rows. Convert to GeoJSON only when you need geometry, round coordinates to a sensible precision, and drop columns nothing reads.
# macOS and Linux; on Windows, run these inside WSL
python -c "import pandas as pd; d = pd.read_csv('raw.csv'); d.round(3).to_csv('data/clean.csv', index=False)"
DuckDB is faster still when the source is a large CSV or Parquet file, because it streams instead of loading everything into memory.
duckdb -c "COPY (SELECT state, ROUND(avg_score, 2) AS avg_score FROM 'raw.parquet' WHERE year = 2025) TO 'data/summary.csv' (HEADER)"
Compress the data files themselves. Gzip handles CSV and GeoJSON well because both are text; brotli usually does better on the JavaScript and CSS bundles.
gzip -9 -k data/summary.csv
brotli -q 11 app.js -o app.js.br
Two smaller wins: cache-hash your asset filenames so a new build invalidates them automatically, and delete dependencies the page never imports. One stray charting library can add hundreds of kilobytes to every page view.
Finally, read the usage limits before you sign up, not after. Pay attention to build minutes, file size per repository or deployment, bandwidth per month, and whether a credit card is required to activate the free tier. A card requirement is fine; it just means a hard spending cap matters more.
Deploy a Static Project

Static deployment is three settings: connect a repository, name the build command, name the output folder. Everything else is a checkbox.
- Push your project to a Git repository. A private repository works on every major platform.
- Create a new project on the host and connect the repository. The exact menu names move around between providers, so look for something labelled Pages, Sites or Workers with a Pages tab.
- Set the build command. For a plain HTML folder there is none. For a generator use the documented build call, for example a Quarto render or an Astro build. If the project already ships a built folder, leave it blank.
- Set the output directory. Common values are public, dist, _site or docs. Point it at the folder that contains index.html.
- Deploy. The platform builds the site and gives you a preview URL before anything goes live.
- Check the preview URL, then promote it to production.
If the build fails, open the log. Nine times out of ten it is a Node version mismatch or a missing dependency directory, both fixed by pinning versions in the repository rather than on the host.
Git-based deploys also buy you previews: every pull request gets its own URL, so an editor can review the change without touching the live story. Rollbacks are a revert commit. For a newsroom, that safety net alone justifies the setup.
Deploy a Small Project to a Cloud Server
Use this path when you need a real runtime, a cron job or a dataset too large to ship to every reader.
Provision the smallest instance from a provider such as DigitalOcean, Hetzner or Lightsail. Community members on Hacker News consistently put a small droplet in the 4-to-8 dollar range as the DIY fallback, and the forum consensus on cheap static hosting is that you should avoid paying for a server at all until a static host actually blocks you.
ssh root@your-server-ip
apt update && apt install -y nginx python3 python3-venv certbot python3-certbot-nginx
Upload the project, keep it out of the web root, and run it under a process manager so it restarts after a reboot.
rsync -avz --exclude '.git' ./ deploy@your-server-ip:/srv/project/
ssh deploy@your-server-ip 'cd /srv/project && gunicorn --bind 127.0.0.1:8000 app:app'
Confirm it works locally with curl on the loopback address before exposing it. Put Nginx in front as a reverse proxy, keep the firewall to ports 22, 80 and 443, and run the app as a non-root user.
Budget for the unglamorous parts: unattended security updates, off-site backups, and a cron job that actually emails you when it fails. A virtual machine does none of that by itself.
Connect a Domain and Enable HTTPS
A clean domain on a free host takes about ten minutes and costs roughly 10 to 15 dollars a year.
- Add the domain in your host’s dashboard. The platform prints the exact nameserver pair or DNS record it expects.
- At your registrar, set those nameservers, or add a CNAME record pointing at the host’s assigned address.
- Wait for the change to propagate, often within the hour but occasionally a day.
- The host issues a TLS certificate automatically on most platforms. If you are on the server path, run certbot with the Nginx plugin instead.
- Turn on the redirect from HTTP to HTTPS, then set the canonical URL in your page metadata.
Two things bite here. If any asset still loads over plain HTTP, browsers block it as mixed content, so search the project for http:// references after switching. And if you have a staging and production URL, set the canonical to production or your search rankings will split across both.
Test the Public Project
A deploy is not done until the public URL behaves. Run this list before you tell anyone the story is live.
- The page loads in under a few seconds on a phone, not just on your laptop.
- Layout holds at 360 pixels wide.
- Data files download: open the network panel and confirm the fetch returns real rows, not an empty array.
- The browser console is clean. A silent JavaScript error often shows up as a blank chart.
- Links resolve, including the data source and methodology pages.
- HTTPS is on and the certificate matches the domain.
For ongoing monitoring, a single scheduled request to an uptime service against your URL is enough for a small team. It costs nothing and catches the two failures that matter: the site is down, or the certificate expired.
Control Costs After Launch
Most surprise bills come from one of five places: traffic, storage, build minutes, a database left switched on, or idle resources nobody remembered creating.
| Project type | Free tier | Comfortable monthly budget | Where the money goes |
|---|---|---|---|
| One-page chart or mapped story | 0 dollars | 0 to 2 dollars | Domain only |
| Full interactive data story | 0 dollars | About 5 to 20 dollars | Domain, higher build minutes, object storage for large files |
| API-backed project with a database | Partly covered | About 15 to 40 dollars | Database size, compute hours, backups |
Prices above are typical US ranges; they vary by region and change over time, so check the provider’s own pricing page before you commit. Figures last checked for 2026.
Then set the guards. Turn on budget alerts at a fraction of what you would actually notice. Configure a hard spending cap where the provider offers one. Delete resources you created for experiments instead of leaving them running. For a database, decide deliberately whether it needs to run continuously or can start on demand, because always-on compute is what turns a free account into a bill.
The fear that a free tier will disappear with no warning is well earned; Heroku removed its free tier and the forums still reference it as the reference example. Mitigation is portability rather than loyalty: keep your build output static, your data in open formats, and your DNS somewhere you control, so moving hosts is a settings change rather than a rewrite.
Common Mistakes and How to Fix Them
Sending the whole dataset to every reader. Putting 40 MB of GeoJSON in the site bundle means nobody sees the chart until that download finishes. The fix I keep coming back to: preprocess to summary columns at build time, compress the file, and load it with fetch on demand.
Publishing data meant to stay private. Anything in a static output folder is public, including a draft story or an API key someone left in a config file. Fix: move secrets to environment variables, and check the repository history, not just the current commit.
Running resources nobody is using. Commenters on developer forums describe forgotten databases and idle instances quietly consuming an allowance. Fix: list every resource once a month and delete what has no purpose.
Shipping without HTTPS. Browsers warn, some features refuse to run, and search visibility suffers. Fix: enable the automatic certificate and redirect before you announce the URL.
Getting the output directory wrong. The build succeeds and the site is blank or 404s. Fix: confirm the output folder contains index.html, and check the build log rather than guessing.
No monitoring. A dead link after a failed deploy goes unnoticed until a reader reports it. Fix: an uptime check and a deploy notification, both free.
For maintenance, keep a short runbook: how to redeploy, where the data comes from, when it was last refreshed. Pin your data source version so the build can be reproduced later, and attribute the dataset in a visible methodology note. When the data updates, readers and editors both want to know what changed.
Frequently Asked Questions
Can I host a data project for free?
Yes, for most projects. A static site built from HTML, CSS, JavaScript and a CSV or GeoJSON file runs at no cost on platforms like GitHub Pages or Cloudflare Pages, and those tiers typically cover more bandwidth and build time than a small newsroom project uses. You pay only when you need scheduled jobs, private data or a live database.
What is the cheapest way to host an interactive data visualization?
Preprocess your data into small summary files, then host the whole thing as a static site. The chart renders client-side from a compressed file under a few hundred kilobytes, so you never need a server. If the visualization calls a live API, add a serverless function for those specific requests and leave everything else static.
Do I need a server for a project that reads CSV or JSON files?
No. If the browser fetches the file and renders it, that is a static project and needs no server. A server only becomes necessary when data must stay private, when a job has to refresh files on a schedule, or when queries need to run against a database rather than downloading a file. Most published stories never reach that point.
How can I stop a cloud project from generating unexpected charges?
Enable budget alerts first, then set a hard spending cap if the provider offers one. Delete idle databases and instances you created for testing, and prefer resources that scale to zero over ones that bill continuously. Run a monthly review of every active resource in your account, not just the ones you remember creating.
Is static hosting suitable for an API or scheduled data update?
Not on its own. Static hosting serves files and can serve serverless functions alongside them, which covers light API work. A scheduled refresh needs a separate trigger, such as a cron service or a workflow on your Git provider, writing the updated data into the repository. That combination covers most newsroom projects without a server.
Start with one classification: is this project static or does it need a runtime? Then estimate the traffic and the file sizes, and pick the lowest-cost host that covers both. A static platform will almost certainly be the answer, and the whole deployment takes an afternoon rather than a budget cycle.


