Skip to main content
Version: Next

Upgrade to 3.0

Web Server: Widget to Component Rename

In Serverpod 3.0, all web server related "Widget" classes have been renamed to "Component" to better reflect their purpose and avoid confusion with Flutter widgets.

The following classes have been renamed:

Old NameNew Name
WidgetComponent
AbstractWidgetAbstractComponent
WidgetRouteComponentRoute
WidgetJsonJsonComponent
WidgetRedirectRedirectComponent
WidgetListListComponent

1. Update Route Classes

Update all route classes that extend WidgetRoute to extend ComponentRoute, and rename them to follow the new naming convention:

Before:

class RouteRoot extends WidgetRoute {

Future<Widget> build(Session session, HttpRequest request) async {
return MyPageWidget();
}
}

After:

class RootRoute extends ComponentRoute {

Future<Component> build(Session session, HttpRequest request) async {
return MyPageComponent();
}
}

2. Update Component Classes

Update all classes that extend Widget to extend Component, and rename them from "Widget" to "Component":

Before:

class MyPageWidget extends Widget {
MyPageWidget({required String title}) : super(name: 'my_page') {
values = {
'title': title,
};
}
}

After:

class MyPageComponent extends Component {
MyPageComponent({required String title}) : super(name: 'my_page') {
values = {
'title': title,
};
}
}

3. Update Abstract Components

If you have custom abstract components, update them from AbstractWidget to AbstractComponent and rename accordingly:

Before:

class CustomWidget extends AbstractWidget {

String toString() {
return '<html>...</html>';
}
}

After:

class CustomComponent extends AbstractComponent {

String toString() {
return '<html>...</html>';
}
}

4. Update Special Component Types

Update references to special component types:

Before:

// JSON responses
return WidgetJson(object: {'status': 'success'});

// Redirects
return WidgetRedirect(url: '/login');

// Component lists
return WidgetList(widgets: [widget1, widget2]);

After:

// JSON responses
return JsonComponent(object: {'status': 'success'});

// Redirects
return RedirectComponent(url: '/login');

// Component lists
return ListComponent(widgets: [widget1, widget2]);

5. Update Route Registration

Update your route registration to use the renamed route classes:

Before:

pod.webServer.addRoute(RouteRoot(), '/');
pod.webServer.addRoute(RouteRoot(), '/index.html');

After:

pod.webServer.addRoute(RootRoute(), '/');
pod.webServer.addRoute(RootRoute(), '/index.html');

Directory Structure

For consistency with the new naming convention, we recommend renaming your widgets/ directories to components/. However, this is not strictly required - the directory structure can remain unchanged if needed.

Class Names

For consistency and clarity, we recommend updating all class names from "Widget" to "Component" (e.g., MyPageWidgetMyPageComponent). While you can keep your existing class names and only update the inheritance, following the new naming convention will make your code more maintainable and consistent with Serverpod's conventions.

Complete Example

Here's a complete example of migrating a simple web page:

Before:

// lib/src/web/widgets/default_page_widget.dart
import 'package:serverpod/serverpod.dart';

class DefaultPageWidget extends Widget {
DefaultPageWidget() : super(name: 'default') {
values = {
'served': DateTime.now(),
'runmode': Serverpod.instance.runMode,
};
}
}

// lib/src/web/routes/root.dart
import 'dart:io';
import 'package:my_server/src/web/widgets/default_page_widget.dart';
import 'package:serverpod/serverpod.dart';

class RouteRoot extends WidgetRoute {

Future<Widget> build(Session session, HttpRequest request) async {
return DefaultPageWidget();
}
}

After:

// lib/src/web/components/default_page_component.dart (renamed file and directory)
import 'package:serverpod/serverpod.dart';

class DefaultPageComponent extends Component {
DefaultPageComponent() : super(name: 'default') {
values = {
'served': DateTime.now(),
'runmode': Serverpod.instance.runMode,
};
}
}

// lib/src/web/routes/root.dart
import 'dart:io';
import 'package:my_server/src/web/components/default_page_component.dart';
import 'package:serverpod/serverpod.dart';

class RootRoute extends ComponentRoute {

Future<Component> build(Session session, HttpRequest request) async {
return DefaultPageComponent();
}
}

// server.dart
pod.webServer.addRoute(RootRoute(), '/');
pod.webServer.addRoute(RootRoute(), '/index.html');