Swup owns the page load lifecycle, and the plugin list is what you are missing
Versatile and extensible page transition library for server-rendered websites 🎉
At a glance
- What is it?
- Swup animates navigation on server-rendered sites by taking over the whole page load, which is why it also has to hand you cache behavior, hooks, and a plugin per missing feature. Read the plugin catalog as the honest inventory of what the core does not do.
- Who is it for?
- Take swup when your pages are server-rendered, your motion is expressed in CSS transitions, and you want history, scroll restoration, and caching handled in one place rather than assembled yourself. Pass on it if your animations live in JavaScript, if you cannot tolerate a cache in front of content that changes without notice, or if you need document head updates out of the box.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 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 October 5, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The README has no install snippet, so the package fields are the setup story
There is no installation command in this README. Setup lives at swup.js.org, and what the repository contributes is the package manifest, which answers the questions you would otherwise have to guess at. These are the published entry points:
"main": "./dist/Swup.cjs",
"module": "./dist/Swup.module.js",
"unpkg": "./dist/Swup.umd.js",
"types": "./dist/types/index.d.ts",
"exports": {
".": {
"types": "./dist/types/index.d.ts",
"import": "./dist/Swup.modern.js",
"require": "./dist/Swup.cjs"
}
}Three details matter more than the rest. The package ships as `swup` with an `amdName` of `Swup`, so an AMD or global consumer expects that spelling. The `unpkg` field points at a UMD build, which is the file a CDN request resolves to, and the README badge checks bundle size for the package with tree shaking of the default export. And `"files": ["src", "dist"]` means the published tarball carries the TypeScript sources next to the built output, so reading the implementation from inside `node_modules` is a supported habit rather than a hack.
The manifest version reads 4.10.0, which matches the latest release listed for the repository.
Swup claims the whole page load, and hooks are where you get control back
The scope claim is the point: swup manages the complete page load lifecycle and animates between the current and next page. Around that core it names caching, smart preloading, native browser history with URL updates, scroll position and anchor link handling, and accessibility improvements. History and scroll are the two that change browser behavior rather than looks, and both are listed as handled by the library rather than left to a plugin.
Hooks are the seam. The documentation offers them for customizing and extending the page load lifecycle, and swup.js.org keeps a section for them. That answers the usual objection to client side navigation, which is that a transition library becomes a black box between two pages; one that exposes the lifecycle lets you run your own code at defined points, and the plugin system reuses that same seam. The official plugins are thin for that reason. A progress bar, smooth scrolling, head updates, and background preloading are lifecycle chores, not rendering work.
Anchor links deserve a specific mention, because they are the quiet failure. A site that jumps to an anchor on load has to keep jumping there after a transition, and when it does not, the symptom is a scroll position that ignores the URL.
Timing is read off your CSS, which is why the js plugin exists
Duration is detected rather than configured. One of the listed features is auto-detecting CSS transitions and animations so that swup waits exactly as long as your stylesheet says, and the getting started page links that behavior as the reason timing lands without hand tuned numbers in the options.
That decision has a direct consequence. If the animation is not a CSS transition or animation, there is nothing to detect, which is why the official js plugin exists to perform animations in JS instead of CSS transitions. Read that plugin first if your motion design comes from a JavaScript animation runtime or if your durations come out of a spring simulation. It is also the place to look when a transition never fires, since a duration swup cannot read is a duration it cannot wait for, and the symptom is a transition that appears to be skipped rather than an error.
Three official themes ship so you can defer that decision: fade, slide, and overlay. Each is a ready-made starting point rather than something you configure from scratch, which is the fastest way to see what the auto-detection expects from your own markup.
The core updates no meta tags and animates no forms
The library is small by design, and its plugin catalog is where the missing behavior becomes visible. Nothing in the base package updates your document head, so the head plugin exists to update meta tags and stylesheets after page loads. Nothing animates form submissions, so the forms plugin covers that. A progress bar while loading is a plugin. Smooth scrolling between visits is a plugin. Preloading pages in the background is a plugin. Improved accessibility for screen readers is a plugin.
That is a coherent design, and it is also the inventory of what you do not get from the package alone. A site that animates transitions and forgets the head plugin keeps the previous page's title, description, and stylesheets, because nothing in the core asks the server for them again. A form that posts normally jumps instead of animating, which reads as a broken page rather than as a missing feature. Both omissions hide in a demo, since a demo starts on the home page with its head already correct.
The debug plugin earns its place in that list. It exists to help when something misbehaves, so reach for it when a transition fires at the wrong moment or when the cache hands back something you did not expect.
The cache is the feature that changes what your server gets to say
Caching has a wider blast radius than animation, because it changes who answers the request. The README names the cache as the mechanism that speeds up subsequent page loads and swup.js.org keeps a dedicated API page for it, so the behavior is configurable rather than hard coded. Once a page is cached, the second visit is answered on the client and the server is not consulted.
Freshness is the bill, and the repository is quiet about it. Nothing in the README explains when a cached entry expires, what happens when server rendered markup changes, or how to force a refresh for a visitor holding a stale copy. A content site that changes its own pages needs answers to those three questions from the documentation before the cache is switched on, and this repository does not contain them.
Preloading sits on the same axis. The preload plugin adds support for preloading pages in the background, so swup can fetch documents the visitor has not asked for yet. That buys perceived speed and spends server bandwidth on guesses, which makes it a hosting budget decision as much as an interface one.
Two microbundle passes produce the four module formats
The build is two commands, and the second one is why a single package serves both a modern bundler and a script tag:
"build": "npm run build:module && npm run build:bundle",
"build:module": "BROWSERSLIST_ENV=modern microbundle src/index.ts -f modern,esm,cjs",
"build:bundle": "BROWSERSLIST_ENV=production microbundle src/Swup.ts -f umd --external none",
"test": "npm run test:unit && npm run test:e2e",
"test:unit": "vitest run --config ./tests/config/vitest.config.ts",
"test:e2e": "npx playwright test --config ./tests/config/playwright.config.ts"The module pass emits modern, ESM, and CJS from `src/index.ts` under `BROWSERSLIST_ENV=modern`, while the bundle pass takes `src/Swup.ts` and produces a single UMD file with `--external none`, which inlines dependencies for a script tag consumer. Type checking is part of linting rather than the build: `lint:ts` runs `tsc --noEmit --skipLibCheck` twice, the second time against `tsconfig.tests.json`, so a test-only type error blocks a commit.
Two more scripts describe the compatibility posture. `lint:compat` runs eslint with `.eslintrc.compat.cjs`, a second config sitting beside the flat `eslint.config.js`, which reads as a deliberate check against the browser targets declared in `.browserslistrc` era tooling rather than an accident of migrating configs. And the tests are split into fast vitest units and Playwright end to end runs, the latter exercised across vendors with BrowserStack.
Version 4 needs its upgrade guide, and the project is asking for maintainers
The README leads with the announcement that swup 4 is released and links two documents beside it: the release notes and an upgrade guide. That pairing is the honest signal about the cost of moving. A major version with its own upgrade guide means code written for swup 3 may need edits rather than a version bump, and the guide, not the README, is where you find out which.
Recent releases stay inside the 4 line: 4.9.1 on 2026-06-10, 4.9.2 on 2026-06-12, and 4.10.0 on 2026-09-03, with the last push to `main` on 2026-09-29. Two patch releases two days apart followed by a minor release three months later is the pace, so a dependency range is a worse fit than a pinned version. The repository does carry a `CHANGELOG.md`, which is where the per version detail lives when you want it offline.
Governance is stated plainly in the same file: the README says the project is looking for maintainers and links the discussion, and it asks for sponsorship through Open Collective or GitHub sponsors. For an adopter that means maintenance questions and roadmap questions have a named place to go, and that the roadmap depends on people who have not signed up yet.
Editorial conclusion
Take swup when your pages are server-rendered, your motion is expressed in CSS transitions, and you want history, scroll restoration, and caching handled in one place rather than assembled yourself. Pass on it if your animations live in JavaScript, if you cannot tolerate a cache in front of content that changes without notice, or if you need document head updates out of the box. Verify two things first: run `npm run test:unit` and `npm run test:e2e` on your own markup to see whether your pages survive a transition, and read the cache API page at swup.js.org, because the README states that the cache speeds up subsequent loads and says nothing about invalidation.
Frequently asked questions
What does swup mean?
Swup is a page transition library for server-rendered websites: it manages the complete page load lifecycle and animates between the current and next page, adding caching, smart preloading, native browser history, and accessibility improvements. The package is published on npm as `swup`, with the CLI name `Swup` and the manifest version at 4.10.0.
Does swup need a bundler, and can I load it from a CDN?
The package publishes a modern ESM build, a CommonJS build, a UMD build, and type declarations, and the manifest sets `unpkg` to `./dist/Swup.umd.js`, which is the file a CDN request resolves to. The README says swup works out of the box with minimal markup and sends setup to swup.js.org rather than listing a build tool requirement.
How do I add a progress bar or smooth scrolling to swup?
Both are official plugins rather than core features: the progress plugin displays a progress bar while loading, and the scroll plugin enables smooth scrolling between visits. A third plugin, the preload plugin, adds support for preloading pages in the background.
Does swup update my page title and meta tags after a transition?
Not in the core package. Meta tags and stylesheets are updated after page loads by the official head plugin, and form submissions are animated by the forms plugin, so both need to be added if your site relies on them.
Which themes ship with swup?
Three official themes are provided: fade, slide, and overlay. They are offered as ready-to-go starting points, and swup auto-detects CSS transitions and animations to time the animation correctly.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/swup-swup)