# Deploying You can host your built Framework app on any static site hosting service, or self-host it with any static site server. This guide covers automating deploys to [GitHub Pages](https://pages.github.com/) with [GitHub Actions](https://github.com/features/actions), and assumes that you are hosting your Framework project’s git repository on GitHub.
If you don’t yet have an app ready to deploy, create one by following our [Getting started guide](./getting-started).
In your git repository, create the file `.github/workflows/deploy.yml` with the following contents: ```yaml name: Deploy on: # Run this workflow whenever a new commit is pushed to main. push: {branches: [main]} # Run this workflow once per day, at 10:15 UTC schedule: [{cron: "15 10 * * *"}] # Run this workflow when triggered manually in GitHub’s UI. workflow_dispatch: {} jobs: deploy: runs-on: ubuntu-latest permissions: contents: read pages: write id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: npm - run: npm ci - run: npm run build - uses: actions/configure-pages@v4 - uses: actions/upload-pages-artifact@v3 with: path: dist - name: Deploy id: deployment uses: actions/deploy-pages@v4 ``` Commit this file to your main branch and push to GitHub. Then follow [GitHub’s instructions](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-with-a-custom-github-actions-workflow) to specify GitHub Actions as the source for GitHub Pages. After you’ve performed these steps, the `deploy.yml` above will automatically build and deploy your app once per day (to keep your data up-to-date), as well as whenever you push new commits to your GitHub repository’s main branch (so you can make changes at any time). You will also be able to manually trigger a deploy through GitHub’s user interface. If you like, you can disable any of these triggers (`push`, `schedule`, or `workflow_dispatch`) by updating the `deploy.yml` file. ### Caching If some of your data loaders take a long time to run, or simply don’t need to be updated every time you build, you can set up caching to automatically re-use existing data from previous builds. To do that, add the following steps to your `deploy.yml` before `npm run build`: ```yaml jobs: deploy: steps: # … - id: date run: echo "date=$(TZ=America/Los_Angeles date +'%Y-%m-%d')" >> $GITHUB_OUTPUT - id: cache-data uses: actions/cache@v4 with: path: src/.observablehq/cache key: data-${{ hashFiles('src/data/*') }}-${{ steps.date.outputs.date }} # … ```
This will only cache data loaders that live under src/data. You’ll need to edit the paths above if you’ve configured a source root other than src, or if the data loaders you want to cache live elsewhere.
This uses one cache per calendar day (in the `America/Los_Angeles` time zone). If you deploy multiple times in a day, the results of your data loaders will be reused on the second and subsequent runs. You can customize the `date` and `cache-data` steps to change the cadence of the caching. For example you could use `date +'%Y-%U'` to cache data for a week or `date +'%Y-%m-%dT%H'` to cache it for only an hour.