Skip to content

Upgrade to LightNet v4

This is the migration guide for upgrading an existing project to the latest LightNet v4 release.

LightNet now targets Astro v6.

  • Sites using LightNet should upgrade their Astro dependency to v6.
  1. Update your site with:
Terminal window
npx @astrojs/upgrade
  1. Follow the Astro v6 migration guide for any manual follow-up steps:

https://docs.astro.build/en/guides/upgrade-to/v6/

LightNet no longer depends on @astrojs/tailwind. That integration was previously needed to support Tailwind CSS v3, but Astro v6 no longer supports Tailwind CSS v3 through @astrojs/tailwind. LightNet now provides a built-in Tailwind implementation instead.

Reference:

https://github.com/withastro/astro/issues/15824

If your site still lists @astrojs/tailwind in its package.json, remove it from your dependencies.

Reconfigure DaisyUI manually if you use it

Section titled “Reconfigure DaisyUI manually if you use it”

DaisyUI was removed from LightNet’s built-in Tailwind configuration. LightNet no longer injects DaisyUI plugin/theme settings automatically.

  • DaisyUI styles are no longer generated by default.
  • Sites using DaisyUI classes (dy- prefixed classes) must configure DaisyUI themselves.

If your site uses DaisyUI utilities/components, install and configure DaisyUI in your project Tailwind config.

This is how LightNet used to configure DaisyUI:

tailwind.config.ts
import daisyui from "daisyui";
const primary = "#E6B15C";
export default {
plugins: [daisyui],
daisyui: {
themes: [
{
lightnet: {
primary,
secondary: primary,
accent: primary,
neutral: "#030712",
error: "#9f1239",
"base-100": "#f9fafb",
"--rounded-box": "0.375rem", // border radius rounded-box utility class, used in card and other large boxes
"--rounded-btn": "0.375rem", // border radius rounded-btn utility class, used in buttons and similar element
"--rounded-badge": "0.375rem", // border radius rounded-badge utility class, used in badges and similar
"--tab-radius": "0.375rem", // border radius of tabs
},
},
],
base: false, // applies background color and foreground color for root element by default
utils: true, // adds responsive and modifier utility classes
logs: false, // Shows info about daisyUI version and used config in the console when building your CSS
prefix: "dy-",
},
};

If your site does not use DaisyUI classes, no action is required.

An experimental LightNet administration UI based on Sveltia CMS was added. This replaces the previous experimental Decap-based admin integration.

  • @lightnet/decap-admin is replaced by @lightnet/sveltia-admin.
  • The admin integration no longer accepts a languages option; languages are resolved from LightNet config.
  1. Replace package imports.
// before
import decapAdmin from "@lightnet/decap-admin";
// after
import lightnetSveltiaAdmin from "@lightnet/sveltia-admin";
  1. Update integration setup and remove languages option.
// before
integrations: [
decapAdmin({
languages: ["en", "de"],
}),
];
// after
integrations: [lightnetSveltiaAdmin({})];

The imagesFolder option was removed from @lightnet/sveltia-admin. Image fields now always use the content-adjacent images directory.

  • imagesFolder is no longer a valid integration option.
  • Passing imagesFolder now throws during Astro integration setup.
  • Sveltia image upload paths are fixed to images.
  1. Remove imagesFolder from your lightnetSveltiaAdmin(...) config.
// before
lightnetSveltiaAdmin({
imagesFolder: "_images",
});
// after
lightnetSveltiaAdmin({});
  1. Rename the media image folder to src/content/media/images if needed.
# before
src/content/media/_images/
# after
src/content/media/images/
  1. Update image paths in media content entries.
// before
{
"image": "./_images/my-image.jpg"
}
// after
{
"image": "./images/my-image.jpg"
}

Move locale access to Astro.locals.i18n.currentLocale

Section titled “Move locale access to Astro.locals.i18n.currentLocale”

LightNet no longer injects Astro i18n routing config during integration setup. Locale-aware code should now read the active locale from Astro.locals.i18n.currentLocale.

  • LightNet no longer configures Astro i18n (locales, defaultLocale, routing) for you.
  • Code paths using Astro.currentLocale must switch to Astro.locals.i18n.currentLocale.
  1. Update locale access in pages and components to read from Astro.locals.i18n.
---
// before
const currentLocale = Astro.currentLocale
// after
const { currentLocale } = Astro.locals.i18n
---
  1. If your project relies on Astro i18n routing for routes outside LightNet, define it explicitly in astro.config.*.

LightNet still rewrites / to /{defaultLocale}.

This is the Astro i18n config LightNet used to generate:

astro.config.ts
export default defineConfig({
i18n: {
defaultLocale: "en",
locales: ["en", "de"],
routing: {
redirectToDefaultLocale: false,
prefixDefaultLocale: true,
fallbackType: "rewrite",
},
},
});

Convert labels to explicit inline locale maps

Section titled “Convert labels to explicit inline locale maps”

Label fields were changed from implicit string values to explicit inline locale maps across config and content. Translation lookups with t(...) now treat string inputs strictly as translation keys.

Example label map:

{
"label": {
"en": "Hello",
"de": "Hallo"
}
}
  • Label fields no longer accept plain strings (including x.* or ln.* values).
  • Label fields must be locale maps scoped to configured site locales.
  • t("...") now treats string input strictly as a translation key and throws when missing.

Updated fields:

  • Config: title, logo.alt, mainMenu[].label
  • Content: languages.label, categories.label, media-collections.label, media-types.label, media[].content[].label, media-types.detailsPage.openActionLabel

Validation rules:

  • Locale-map keys must be valid BCP-47 tags.
  • The default site locale is required.
  • Other configured site locales are optional.
  • Locale keys must be configured site locales.
  • Extra locale keys are rejected.
  • Label values must be non-empty strings.
  1. Convert label strings to locale maps in config.
// before
{
"title": "My Library",
"mainMenu": [{ "href": "/about", "label": "About" }]
}
// after
{
"title": { "en": "My Library" },
"mainMenu": [{ "href": "/about", "label": { "en": "About" } }]
}
  1. Convert content label fields to locale maps.
// before
{
"label": "Books"
}
// after
{
"label": {
"en": "Books",
"de": "Bücher"
}
}
  1. Ensure keys passed as strings to t(...) exist in translation files.

Drop the x. prefix from custom translation keys

Section titled “Drop the x. prefix from custom translation keys”

User translation keys no longer need the x. prefix. You can now use direct keys like site.title and home.bbq.title while built-in LightNet keys remain under ln.*.

Example:

# before
x.home.title: "Welcome"
# after
home.title: "Welcome"
  • None.

Add explicit type to media content entries

Section titled “Add explicit type to media content entries”

Media item content entries now use explicit typed objects so storage intent is clear (upload vs link).

Examples:

  • { "type": "upload", "url": "/files/example.pdf", "label"?: ... }
  • { "type": "link", "url": "https://example.com/file.pdf", "label"?: ... }
  • content entries are expected to use explicit type values (upload or link).

Update media content entries to include type.

// before
{
"content": [
{ "url": "/files/my-book.pdf", "label": { "en": "Read PDF" } }
]
}
// after
{
"content": [
{
"type": "upload",
"url": "/files/my-book.pdf",
"label": { "en": "Read PDF" }
}
]
}

Use type: "upload" for site-managed files and type: "link" for external URLs.

Move collection membership into media-collections

Section titled “Move collection membership into media-collections”

Collection ownership was reversed from media[].collections to media-collections[].mediaItems. Collections now own membership and order directly.

  • media entries no longer support the collections field.
  • media-collections entries now define membership using mediaItems.
  • Collection ordering is now defined by the order of IDs in mediaItems.
  1. Remove collections from each media item.
src/content/media/my-book--en.json
{
"title": "My book",
"collections": [
{ "collection": "learn-series" },
{ "collection": "featured", "index": 2 }
]
}
// after
{
"title": "My book"
}
  1. Add media membership and order to each media collection.
src/content/media-collections/learn-series.json
{
"label": { "en": "Learn Series" },
"mediaItems": ["my-book--en", "another-item--en"]
}

If you previously used per-item index, convert that ordering into mediaItems array order.

Move detailsPage.coverStyle to coverImageStyle

Section titled “Move detailsPage.coverStyle to coverImageStyle”

Deprecated media-types.detailsPage.coverStyle support was removed. Cover styling now belongs at top-level coverImageStyle.

  • detailsPage.coverStyle is no longer supported.
  • Automatic schema migration from detailsPage.coverStyle to coverImageStyle was removed.

Move cover style values to top-level coverImageStyle in each media type file.

// before
{
"detailsPage": {
"layout": "default",
"coverStyle": "book"
}
}
// after
{
"coverImageStyle": "book",
"detailsPage": {
"layout": "default"
}
}

Media items no longer require commonId.

  • In lightnet, media item schema validation now accepts entries without commonId.
  • Translation lookup now treats missing commonId as standalone and returns no translations for that item.
  • In @lightnet/sveltia-admin, the Common ID field is now optional in the media item editor.

MediaGallerySection props were renamed and layout defaults were updated to improve API clarity.

Example updated usage:

<MediaGallerySection items={items} itemWidth="narrow" layout="grid" />
  • layout (old item style prop) was renamed to itemWidth.
  • Old layout values ("book" | "video" | "portrait" | "landscape") were removed.
  • itemWidth now supports "infer" | "narrow" | "wide" and defaults to "infer".
  • viewLayout was renamed to layout.
  • Default layout is now "carousel".
  • Old prop names layout (style meaning) and viewLayout are no longer supported.
  • itemWidth="infer" uses the first 10 media items to choose a width:
    • more landscape images (width > height) => "wide"
    • otherwise => "narrow"

Update component usage to the new prop names and values.

<!-- before -->
<MediaGallerySection items={items} layout="book" viewLayout="grid" />
<!-- after -->
<MediaGallerySection items={items} itemWidth="narrow" layout="grid" />
<!-- after (explicit inferred width, default behavior) -->
<MediaGallerySection items={items} itemWidth="infer" layout="grid" />

coverImageStyle is now sourced from each media type configuration.

Replace Material Design Icons with Lucide icons across LightNet.

LightNet now uses the Lucide icon set for a more consistent and modern visual language.

Projects should update custom icons used in media types or with the <Icon /> component to Lucide icon names prefixed with lucide--.

Material Design Icons with the mdi-- prefix are now deprecated and will be removed in the next major release.