User Management
SvelteForge Admin provides full CRUD operations for user management, powered by SvelteKit form actions and Svelte 5 reactivity. Users are stored in SQLite via Drizzle ORM with Argon2id password hashing, role-based access control, and comprehensive server-side validation.
User Table
The user table loads all users server-side through the load function in users/+page.server.ts. Data is fetched from the Drizzle ORM users table, ordered by creation date (newest first).
Features
- Sortable columns — Click column headers to sort by name, email, username, role, or creation date.
- Search filtering — Real-time filtering across name, email, and username using
$stateand$derivedrunes from Svelte 5. - Pagination — The
data-table-paginationcomponent provides page navigation with configurable page sizes. - Page size selector — Choose between 10, 25, or 50 rows per page. The selection persists across navigation.
- CSV and JSON export — Export visible or all user data using utility functions
from
#lib/utils/export.ts.
Server-Side Data Loading
// users/+page.server.ts — load function
export const load: PageServerLoad = async () => {
const allUsers = db.select().from(users).orderBy(desc(users.createdAt)).all();
return { users: allUsers };
}; Creating Users
New users are created through the user-form-dialog.svelte component, which renders a
form inside a dialog. Only administrators can create users.
Form Fields
| Field | Requirements |
|---|---|
| Name | Required, displayed in the UI and exports |
| Required, must be unique across all users | |
| Username | 3-31 characters, lowercase alphanumeric only |
| Password | Required, hashed with Argon2id before storage |
| Role | Select from Admin, Editor, or Viewer |
Server-Side Validation
The create form action in users/+page.server.ts performs the following checks
before inserting a new user:
- Username format validation (3-31 lowercase alphanumeric characters)
- Email uniqueness check against existing users
- Password requirements enforcement
- Argon2id hashing of the password before database insertion
The form uses SvelteKit's use:enhance for progressive enhancement, keeping the page interactive
while the server processes the request.
Editing Users
The same user-form-dialog.svelte component handles editing when opened in edit mode.
The dialog pre-populates all fields with the selected user's current data.
- All fields are editable, including role assignment.
- The
updateform action validates changes server-side with the same rules as creation. - Last-admin protection — The server prevents demoting the last remaining admin to a lower role, ensuring at least one admin always exists.
Deleting Users
User deletion is handled by the delete-confirm-dialog.svelte component, which requires
explicit confirmation before proceeding.
Safety Checks
- Self-deletion prevention — Users cannot delete their own account.
- Last-admin protection — The system blocks deletion if it would remove the last administrator.
Bulk Delete
Select multiple users via checkboxes and delete them in a single action. The bulk delete operation:
- Automatically filters out the current user from the selection.
- Blocks the operation if deleting the selected users would remove all remaining administrators.
- Uses the
bulkDeleteform action, which processes all deletions in a single database transaction.
Role-Based Access Control (RBAC)
SvelteForge Admin implements a three-tier role system. The first user to register is automatically assigned the Admin role.
Role Capabilities
| Capability | Admin | Editor | Viewer |
|---|---|---|---|
| View dashboard | Yes | Yes | Yes |
| View users list | Yes | Yes | Yes |
| Create users | Yes | No | No |
| Edit users | Yes | No | No |
| Delete users | Yes | No | No |
| Manage roles | Yes | No | No |
| Manage content | Yes | Yes | No |
| View analytics | Yes | Yes | No |
| Manage settings | Yes | No | No |
Role Changes
Administrators can change a user's role via a dedicated role change dialog. A confirmation step is required, and the system enforces that at least one admin must remain at all times. Permission checks run inside the SvelteKit form actions to prevent unauthorized role modifications.
Export
User data can be exported in two formats using shared utility functions from #lib/utils/export.ts:
- CSV export — Properly escapes values containing commas, double quotes, and newlines. Fields are wrapped in quotes when necessary, following RFC 4180.
- JSON export — Pretty-printed with 2-space indentation for readability.
Both formats trigger a browser download with an appropriately named file.
Svelte 5 Patterns Used
The user management module demonstrates several Svelte 5 patterns throughout:
$state— Reactive state for search query, current page number, and page size.$derived— Computed values for filtered user lists and paginated slices, automatically updating when dependencies change.use:enhance— SvelteKit's progressive enhancement directive on all forms, enabling non-blocking submissions without full page reloads.{@render}— Snippet-based rendering for table cell content, enabling reusable column templates.
// Svelte 5 reactive patterns in the users page
let search = $state('');
let currentPage = $state(1);
let pageSize = $state(10);
let filteredUsers = $derived(
users.filter((u) =>
u.name.toLowerCase().includes(search.toLowerCase()) ||
u.email.toLowerCase().includes(search.toLowerCase())
)
);
let paginatedUsers = $derived(
filteredUsers.slice((currentPage - 1) * pageSize, currentPage * pageSize)
); Need More Than User Management?
DashboardPack premium admin templates include full CRUD modules for Orders, Products, Customers, Invoices, and more — all built with Svelte 5 and SvelteKit, ready for production.
Explore DashboardPack Premium