Deployment & Performance
AdminLTE is a static HTML/CSS/JS template — there’s nothing exotic about deploying it. But there are a handful of choices that meaningfully change page weight, time-to-interactive, and CDN reliability. This page documents the ones worth getting right.
What to deploy
The deployable artefact is everything under dist/ plus your own
HTML / server-rendered templates:
dist/
├── css/ ← stylesheets (LTR + RTL, dev + minified)
│ ├── adminlte.css
│ ├── adminlte.min.css
│ ├── adminlte.rtl.css
│ └── adminlte.rtl.min.css
├── js/ ← JavaScript bundle (dev + minified)
│ ├── adminlte.js
│ └── adminlte.min.js
└── assets/ ← demo images / fonts (replace with your own)
You don’t ship src/, node_modules/, or the demo HTML
if you’re embedding AdminLTE into your own app.
Always use the .min variants in production
The minified builds are the same code with whitespace stripped and identifiers
shortened. For adminlte.css the saving is roughly 15-20%; for
adminlte.js it’s bigger (about 30% after gzip). The non-minified
files are useful in development for readable source-map debugging — never
serve them to users.
| Asset | Dev | Production |
|---|---|---|
| Stylesheet | dist/css/adminlte.css |
dist/css/adminlte.min.css
|
| Script | dist/js/adminlte.js |
dist/js/adminlte.min.js
|
| RTL stylesheet | dist/css/adminlte.rtl.css |
dist/css/adminlte.rtl.min.css
|
Compression at the edge
Make sure your web server / CDN gzips (or brotlis) responses for the relevant content types:
# nginx
gzip on;
gzip_types text/css application/javascript text/html image/svg+xml;
gzip_comp_level 6;
# Apache
AddOutputFilterByType DEFLATE text/css application/javascript text/html image/svg+xml
Cloudflare, Vercel, Netlify, and most managed hosting do this automatically.
Verify with
curl -I -H "Accept-Encoding: gzip" your-page-url and
look for content-encoding: gzip in the response.
Cache headers
The dist artefacts have content hashes in their filenames only if you wire it up via your bundler — AdminLTE itself ships fixed filenames. Two reasonable strategies:
-
Short cache + version query string (simple, works without a build pipeline):
<link rel="stylesheet" href="/dist/css/adminlte.min.css?v=4.0.0" /> <script src="/dist/js/adminlte.min.js?v=4.0.0"></script>Set
Cache-Control: public, max-age=86400(1 day) at the server. Bump?v=on every release to force cache invalidation. -
Fingerprinted filenames (production-grade, requires a bundler):
Let your bundler emit
adminlte.[hash].min.cssand reference that hash in your HTML. SetCache-Control: public, max-age=31536000, immutable(1 year). This is what Vite/Webpack/Rollup do by default if you import AdminLTE through them.
CDN integrity hashes
If you load AdminLTE from a public CDN (jsDelivr, unpkg), include a Subresource Integrity (SRI) hash so a compromised CDN can’t serve malicious JavaScript silently:
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/admin-lte@4.0.0/dist/css/adminlte.min.css"
integrity="sha384-PASTE_THE_HASH_HERE"
crossorigin="anonymous"
/>
You can get the hash from the jsDelivr file detail page — click any file and copy the “SRI” line. Do the same for Bootstrap, Popper, OverlayScrollbars, and Bootstrap Icons.
For private-hosted assets, generate the hash yourself:
openssl dgst -sha384 -binary dist/css/adminlte.min.css | openssl base64 -A
Loading order matters
Get the script order right or things break silently:
<head>
<!-- 1. Bootstrap Icons (font CSS) — load first so icons render with the page -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css" />
<!-- 2. OverlayScrollbars (optional, for the sidebar scroller) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.11.0/styles/overlayscrollbars.min.css" />
<!-- 3. AdminLTE — includes Bootstrap CSS via its imports -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/admin-lte@4.0.0/dist/css/adminlte.min.css" />
</head>
<body>
…
<!-- Scripts at the END of body -->
<!-- 4. Popper (Bootstrap dependency for dropdowns/tooltips/popovers) -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
<!-- 5. Bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.min.js"></script>
<!-- 6. OverlayScrollbars -->
<script src="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.11.0/browser/overlayscrollbars.browser.es6.min.js"></script>
<!-- 7. AdminLTE — must load AFTER Bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/admin-lte@4.0.0/dist/js/adminlte.min.js"></script>
</body>
Defer or async?
The AdminLTE bundle waits for DOMContentLoaded before wiring its
data API, so defer is safe and recommended:
<script defer src="/dist/js/adminlte.min.js"></script>
Don’t use async — the script could execute before its
dependencies (Bootstrap, Popper) have parsed, and listeners would attach to
elements that don’t exist yet.
Critical CSS
For sub-1-second first paint, inline the styles that the above-the-fold layout
uses (header + brand + first visible content) and load the rest of
adminlte.min.css asynchronously:
<style>/* extracted critical CSS for /dashboard */</style>
<link
rel="preload"
as="style"
href="/dist/css/adminlte.min.css"
onload="this.onload=null;this.rel='stylesheet'"
/>
<noscript><link rel="stylesheet" href="/dist/css/adminlte.min.css" /></noscript>
Extract critical CSS with a tool like Critters or Penthouse as part of your build. For dashboards behind a login (where first-load speed matters less than for marketing pages), this is usually overkill.
Preload key assets
Push critical resources to the browser before it discovers them in the HTML:
<link rel="preload" as="style" href="/dist/css/adminlte.min.css" />
<link rel="preload" as="font" href="/fonts/source-sans-3.woff2" type="font/woff2" crossorigin />
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
Only preload what’s used on every page. Preloading per-route assets in a shared layout wastes bandwidth.
Lazy-loading sub-pages
If your dashboard has many routes and the JS is server-rendered HTML per route, prefer per-route CSS imports rather than one mega-stylesheet. AdminLTE’s core CSS is small (~44KB gzipped) but page-specific styles (charts, calendars, tables) can add up — only load them where they’re used.
For SPAs, code-split heavy integrations:
// Don't bundle the calendar app into the main chunk
const Calendar = () => import("./Calendar.vue")
Bundle size budget
The current published dist/ artefacts gzip to:
| Asset | Size (gzip) |
|---|---|
adminlte.min.css |
~40 KB |
adminlte.rtl.min.css |
~40 KB |
adminlte.min.js |
~5 KB |
The full first-page payload (HTML + Bootstrap + AdminLTE + Bootstrap Icons +
Popper + OverlayScrollbars) is around 180 KB gzipped when
loaded from CDN. The CI build enforces a bundlewatch check that
fails if any asset crosses its budget.
Service workers / offline support
AdminLTE is just static files — caching them in a service worker works without changes. A minimal Workbox config:
import { precacheAndRoute } from "workbox-precaching"
precacheAndRoute([
{ url: "/dist/css/adminlte.min.css", revision: "4.0.0" },
{ url: "/dist/js/adminlte.min.js", revision: "4.0.0" },
// ...your own pages
])
Removing dev-only files before deploy
If you’re deploying the demo dist/ folder verbatim, strip these
patterns from the upload:
-
*.map(source maps — leak source code to anyone who opens devtools) **/html/(the Astro intermediate build, if present)**/.astro/(Astro cache)
For rclone / rsync:
rsync -avz --delete \
--exclude='*.map' \
--exclude='html/' \
--exclude='.astro/' \
dist/ user@server:/var/www/your-app/
A note on Cloudflare cache
Cloudflare’s default Browser Cache TTL is 4 hours. If you push a new release and want users to see it immediately, purge the affected paths from the Cloudflare dashboard or API. Otherwise, users on cached pages will see your old CSS / JS for up to four hours.
Where to next
- Customization — change colours, sidebar width, breakpoints before you deploy
- Recommended Integrations — pick lightweight libraries for the things AdminLTE doesn’t bundle
- Accessibility — make sure your deployed pages keep their a11y guarantees