Let Yii's Gii Write Your CRUD Boilerplate (Then Read What It Wrote)
Yii's Gii generator turns a database table into a working model, controller, and views in minutes. Here's how to enable it safely, generate a Post CRUD, and handle the cleanup it always needs.
06 Aug 2025, 18:48 UTC

Every project has the same first week: create the table, write the model, write the controller actions, write four forms and a list view, wire up validation, repeat for the next table. None of it is hard, and none of it is why you were hired. Yii ships with a code generator called Gii that produces exactly this scaffolding from your database schema, and if you treat it as a starting point rather than a finished product, it can cut days of boilerplate down to minutes.
What Gii actually is
Gii is a module bundled with Yii 2 (the yiisoft/yii2-gii package) that generates code from templates. It offers generators for models, CRUD, controllers, forms, modules, and extensions. The two you'll use constantly are:
- Model generator — reads a database table and produces an ActiveRecord class with attribute labels, validation rules inferred from column types, and relations if foreign keys exist.
- CRUD generator — takes a model class and produces a controller with
index/view/create/update/deleteactions, a search model, and the corresponding views.
It runs either as a web interface at /gii or from the console via ./yii gii. The web UI is friendlier for previewing which files will be created or overwritten before you commit to anything.
Enabling it safely
Gii should only be reachable in development. In a basic-app-style config/web.php, it's typically registered like this:
if (YII_ENV_DEV) {
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
'allowedIPs' => ['127.0.0.1', '::1'],
];
}Two things matter here. First, the YII_ENV_DEV guard keeps the module out of production entirely — do not rely on allowedIPs alone on a public server, because a misconfigured proxy can make remote clients appear local. Second, if you work inside Docker or a VM, add the host's IP (e.g. 172.17.0.1) or you'll get a 403 and spend ten minutes wondering why.
For the console version, add the same module block to config/console.php. Console Gii is handy in scripts, but the web UI's diff preview is worth the browser trip when files already exist.
Worked example: a Post CRUD
Assume a fresh Yii 2.x install and this migration already applied:
CREATE TABLE post (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
body TEXT NOT NULL,
status TINYINT NOT NULL DEFAULT 0,
created_at INT NOT NULL
);Then, in the browser at http://localhost/gii:
- Model Generator: table name
post, model classPost. Check the preview — it should show one new file,models/Post.php. Generate. - CRUD Generator: model class
app\models\Post, controller classapp\controllers\PostController. Preview shows the controller, aPostSearchmodel, and views underviews/post/. Generate. - Visit
/postand click through list, create, update, and delete.
Verification is simple: the index page renders a GridView with sorting, the create form rejects an empty title (validation came free from the NOT NULL column), and a created record appears in the list. If the form submits but nothing validates, the usual cause is a mismatch between the model's rules() and the actual schema — regenerate or fix the rules by hand.
The generated Post::rules() will look roughly like:
public function rules()
{
return [
[['title', 'body', 'created_at'], 'required'],
[['body'], 'string'],
[['status', 'created_at'], 'integer'],
[['title'], 'string', 'max' => 255],
];
}That's a faithful translation of the schema — which is both the strength and the catch.
The trade-off: generated code is schema-shaped, not domain-shaped
Gii infers validation from column types, so status becomes "any integer" rather than "one of draft/published", and created_at is marked required and editable in the form even though your application should set it. Expect a cleanup pass on every generated model: tighten rules, remove attributes from forms that users shouldn't touch, and replace the default dropdowns and textareas with widgets that fit the domain.
Two other limitations worth planning around:
- Schema drift. Add a column later and Gii won't know. You either regenerate (and lose manual edits to that file) or update by hand. A common pattern is to keep generated models in a
basenamespace and extend them, so regeneration is safe — Gii's model generator supports this via the "base class" and template options. - Style mismatch. Output follows Yii's defaults. If your team uses different conventions, create a custom template (copy
vendor/yiisoft/yii2-gii/src/generators/crud/defaultinto your project and point the generator at it) rather than hand-editing every generated file forever.
Also, don't let the speed become a substitute for understanding. The generated controller is a compact, correct example of Yii's action flow, filters, and model loading — read it once before you start deleting parts of it.
Make it stick
The actionable version: spin up a fresh Yii 2.x project, enable Gii behind YII_ENV_DEV, generate a model plus CRUD for one real table from your current project, and time how long the cleanup pass takes versus writing it from scratch. If you regenerate often, invest an hour in a custom template that matches your house style — that's where Gii stops being a demo trick and becomes part of the build process.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.