Getting Started with Yii2: Installation, Structure & Configuration

Welcome to Phase 1 of the Yii2 Framework series! This is where everything begins — your development environment, your first project, and your first look at how Yii2 thinks.
By the end of this post you'll have a working Yii2 application running locally, understand every folder in the project tree, and know how to configure the framework for different environments.
What You'll Learn
Learning Outcomes:
✅ Install PHP 8.x, Composer, and Yii2 on your machine
✅ Understand the difference between the Basic and Advanced templates
✅ Navigate the Yii2 directory structure with confidence
✅ Read and write Yii2 configuration files
✅ Use the service locator to access built-in application components
✅ Understand the Yii2 request lifecycle from browser to response
Prerequisites
Before starting, make sure you have:
- PHP 8.1+ installed (
php -v) - Composer installed (
composer -V) - A terminal / command line you're comfortable with
- Basic PHP knowledge — functions, classes, namespaces, interfaces
If you're new to Composer, it's PHP's dependency manager — the equivalent of npm for Node.js or pip for Python. Install it from getcomposer.org.
Step 1: Install PHP 8.x
Yii2 requires PHP 8.0 or higher. The recommended version is PHP 8.2+.
macOS
# Using Homebrew
brew install php
# Verify
php -v
# PHP 8.2.x (cli) ...Ubuntu / Debian
sudo apt update
sudo apt install php8.2 php8.2-cli php8.2-mbstring php8.2-xml \
php8.2-curl php8.2-intl php8.2-pdo php8.2-mysql php8.2-zip
php -vWindows
Download the latest PHP for Windows from windows.php.net. Extract to C:\php and add it to your PATH.
Required PHP Extensions
Yii2 needs these extensions. Most are bundled with standard PHP installs:
| Extension | Purpose |
|---|---|
mbstring | Multi-byte string support |
intl | Internationalization |
xml | XML processing |
curl | HTTP client |
pdo + pdo_mysql / pdo_pgsql | Database access |
fileinfo | File upload handling |
zip | Asset publishing |
Check what you have:
php -m | grep -E "mbstring|intl|xml|curl|pdo|fileinfo|zip"Step 2: Install Composer
# macOS / Linux
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
# Verify
composer -V
# Composer version 2.x.xStep 3: Create Your First Yii2 Project
Yii2 provides two official project templates. Here is what each one is for:
| Template | Use case |
|---|---|
| Basic | Single-application sites, APIs, learning Yii2 |
| Advanced | Multi-app projects (separate frontend + backend) |
Start with Basic. You can always migrate to Advanced later. Advanced adds significant complexity that isn't needed until you have a team working on separate frontend/backend apps.
Create a Basic Project
composer create-project --prefer-dist yiisoft/yii2-app-basic myapp
cd myappComposer will fetch Yii2 and all its dependencies. This takes a minute or two on first run.
Run the Development Server
php yii serve
# Server started on http://localhost:8080/Open http://localhost:8080 in your browser. You should see the Yii2 welcome page — "Congratulations!" with the About, Contact, and Login links in the header.
Step 4: Understanding the Project Structure
This is one of the most important things to internalize early. Everything in Yii2 has a deliberate location.
myapp/
├── assets/ # Asset bundle definitions (CSS/JS registrations)
├── commands/ # Console command classes
├── config/ # Application configuration files
│ ├── web.php # Web application config (main)
│ ├── console.php # Console application config
│ ├── params.php # Shared application parameters
│ └── db.php # Database connection config
├── controllers/ # Web controller classes
│ ├── SiteController.php
│ └── ...
├── models/ # Model classes (Active Record + form models)
├── runtime/ # Generated runtime files (logs, cache, debug data)
├── tests/ # Codeception test suite
├── vendor/ # Composer dependencies (don't touch)
├── views/ # View templates (.php files)
│ ├── layouts/ # Layout templates (site/main.php)
│ └── site/ # Views for SiteController
├── web/ # Document root — the ONLY public directory
│ ├── index.php # Entry script (all requests go here)
│ ├── css/ # Published CSS assets
│ └── js/ # Published JS assets
├── .gitignore
├── composer.json
├── composer.lock
└── yii # Console entry scriptCritical rule: Your web server's document root must point to the web/ directory, NOT the project root. The config/, models/, and vendor/ directories must never be publicly accessible.
The Entry Script: web/index.php
All HTTP requests are routed through a single file:
<?php
// Set error reporting in development
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';
$config = require __DIR__ . '/../config/web.php';
(new yii\web\Application($config))->run();This bootstraps the Yii2 application with the configuration from config/web.php, then calls run() which handles the incoming request and sends the response. That's it — four lines of real logic.
Step 5: Understanding Configuration
Yii2's configuration system is plain PHP arrays. There's no YAML, no XML, no annotations — just PHP returning an associative array that describes how your application is assembled.
The Main Config: config/web.php
<?php
$params = require __DIR__ . '/params.php';
$db = require __DIR__ . '/db.php';
$config = [
'id' => 'basic', // Application ID
'basePath' => dirname(__DIR__), // Root path of the app
'bootstrap' => ['log'], // Components to bootstrap at startup
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
'components' => [ // Built-in component registration
'request' => [
'cookieValidationKey' => 'your-secret-key-here',
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'db' => $db,
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [],
],
],
'params' => $params,
];
if (YII_ENV_DEV) {
// Debug and Gii only in development
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
'class' => 'yii\debug\Module',
'allowedIPs' => ['127.0.0.1', '::1'],
];
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
'allowedIPs' => ['127.0.0.1', '::1'],
];
}
return $config;Database Config: config/db.php
<?php
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=myapp',
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4',
];Shared Parameters: config/params.php
<?php
return [
'adminEmail' => 'admin@example.com',
'senderEmail' => 'noreply@example.com',
'senderName' => 'My App',
];Access parameters anywhere in the app:
$email = Yii::$app->params['adminEmail'];Step 6: The Service Locator
Yii2 uses a service locator pattern — Yii::$app is a global object that holds all registered components. You access them by name:
Yii::$app->db // Database connection
Yii::$app->cache // Cache component
Yii::$app->user // Current user / auth component
Yii::$app->request // HTTP request object
Yii::$app->response // HTTP response object
Yii::$app->session // Session
Yii::$app->mailer // Email mailer
Yii::$app->urlManager // URL generation and parsingThese are lazy-loaded singletons — a component is only instantiated the first time you access it.
// Log a message
Yii::info('User logged in', 'app.auth');
// Get query string param
$page = Yii::$app->request->get('page', 1);
// Redirect
return Yii::$app->response->redirect('/login');
// Check if user is logged in
if (Yii::$app->user->isGuest) {
Yii::$app->user->loginRequired();
}Step 7: Aliases and Path Resolution
Yii2 uses aliases to avoid hardcoded paths throughout your code.
| Alias | Resolves to |
|---|---|
@app | Application base path (project root) |
@webroot | web/ directory |
@web | Base URL for the current request |
@vendor | vendor/ directory |
@yii | Yii2 framework directory |
@runtime | runtime/ directory |
Use them everywhere:
// Read a file relative to the project root
$path = Yii::getAlias('@app/data/config.json');
// Generate a URL to a public file
$url = Yii::getAlias('@web/images/logo.png');
// Write to runtime
$logPath = Yii::getAlias('@runtime/logs/app.log');Define custom aliases in your config:
'aliases' => [
'@uploads' => '@webroot/uploads',
'@data' => '@app/data',
],Step 8: The Request Lifecycle
Understanding what happens when a browser hits your app is essential for debugging.
The key steps are:
- URL parsing —
UrlManagerconverts the incoming URL to a route (controller/action) - Controller creation — Yii2 instantiates the controller class
- Filter execution —
beforeAction()filters run (access control, auth, etc.) - Action execution — The action method runs and returns a result
- View rendering — The controller renders a view template into HTML
- Response dispatch — Yii2 sends headers + body to the browser
Step 9: Environment-Specific Configuration
In production you want different settings than in development (debug off, different DB, etc.). The standard Yii2 approach uses the YII_ENV constant and PHP's array_merge pattern.
The Environment Constants
// In web/index.php — set BEFORE loading Yii
defined('YII_DEBUG') or define('YII_DEBUG', true); // false in production
defined('YII_ENV') or define('YII_ENV', 'dev'); // 'prod' in productionMerging Configs Per Environment
A clean approach is to have a base config and environment overlays:
config/
├── web.php # Shared base config
├── web-local.php # Local overrides (gitignored)
├── db.php # DB for dev
├── db-prod.php # DB for production (never committed)
└── params.php # Shared paramsThen in web/index.php:
$config = require __DIR__ . '/../config/web.php';
// Merge local overrides if they exist (not committed to git)
$localConfig = __DIR__ . '/../config/web-local.php';
if (is_file($localConfig)) {
$config = yii\helpers\ArrayHelper::merge($config, require $localConfig);
}
(new yii\web\Application($config))->run();web-local.php is your personal machine's config, added to .gitignore:
<?php
// config/web-local.php — NOT committed to git
return [
'components' => [
'db' => [
'dsn' => 'pgsql:host=localhost;dbname=myapp_dev',
'username' => 'myuser',
'password' => 'mypassword',
],
'mailer' => [
'useFileTransport' => true, // Don't actually send emails in dev
],
],
];Important: Add config/web-local.php and config/db-prod.php to .gitignore immediately. Database passwords must never be committed to version control.
Using .env Files
For teams that prefer .env files, use the vlucas/phpdotenv package:
composer require vlucas/phpdotenv// web/index.php — before loading Yii config
$dotenv = Dotenv\Dotenv::createImmutable(dirname(__DIR__));
$dotenv->safeLoad();// config/db.php
return [
'class' => 'yii\db\Connection',
'dsn' => $_ENV['DB_DSN'] ?? 'mysql:host=localhost;dbname=myapp',
'username' => $_ENV['DB_USER'] ?? 'root',
'password' => $_ENV['DB_PASS'] ?? '',
];Step 10: Your First Controller and View
Let's create something real. Add a HelloController with a custom action:
Create the Controller
<?php
// controllers/HelloController.php
namespace app\controllers;
use yii\web\Controller;
class HelloController extends Controller
{
public function actionIndex(): string
{
return $this->render('index', [
'greeting' => 'Hello from Yii2!',
]);
}
public function actionGreet(string $name = 'World'): string
{
return $this->render('greet', [
'name' => $name,
]);
}
}Create the Views
<?php
// views/hello/index.php
/** @var yii\web\View $this */
/** @var string $greeting */
?>
<h1><?= htmlspecialchars($greeting, ENT_QUOTES, 'UTF-8') ?></h1>
<p>Welcome to your first Yii2 controller.</p>
<p><?= \yii\helpers\Html::a('Try greeting', ['hello/greet', 'name' => 'Yii2']) ?></p><?php
// views/hello/greet.php
/** @var yii\web\View $this */
/** @var string $name */
$this->title = "Hello, $name!";
?>
<h1>Hello, <?= htmlspecialchars($name, ENT_QUOTES, 'UTF-8') ?>!</h1>
<p><?= \yii\helpers\Html::a('← Back', ['hello/index']) ?></p>Try It
Visit http://localhost:8080/hello and http://localhost:8080/hello/greet?name=PHP.
Notice the URL pattern: /controller/action. This is Yii2's default routing — HelloController::actionGreet() maps to /hello/greet. No manual route registration required.
Step 11: Enabling Pretty URLs
Out of the box, Yii2 uses query-string URLs like index.php?r=hello/greet. Pretty URLs look like /hello/greet. Enable them in two steps.
1. Update config/web.php
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false, // Hide index.php from URLs
'rules' => [],
],2. Configure Your Web Server
Nginx:
server {
listen 80;
server_name myapp.local;
root /path/to/myapp/web;
index index.php;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}Apache (.htaccess in web/):
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
# prevent httpd from serving dotfiles (.htaccess, .htpasswd, etc.)
RewriteRule /\. - [f]
# if a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward the request to index.php
RewriteRule . index.phpPHP built-in server (development only):
php yii serve already handles this — pretty URLs work automatically.
Setting Up a Database
Let's connect to MySQL/PostgreSQL so you're ready for Active Record in Phase 3.
Create the Database
# MySQL
mysql -u root -p
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
EXIT;
# PostgreSQL
psql -U postgres
CREATE DATABASE myapp;
\qUpdate config/db.php
<?php
// MySQL
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=myapp;charset=utf8mb4',
'username' => 'root',
'password' => 'your_password',
'charset' => 'utf8mb4',
'tablePrefix' => '',
];<?php
// PostgreSQL
return [
'class' => 'yii\db\Connection',
'dsn' => 'pgsql:host=127.0.0.1;dbname=myapp',
'username' => 'postgres',
'password' => 'your_password',
];Test the Connection
php yii migrate
# If the DB is configured correctly, you'll see:
# No new migrations found. Your system is up-to-date.Exploring the Debug Toolbar
In development mode (YII_ENV=dev), Yii2 loads the Debug Toolbar automatically. You'll see a small bar at the bottom of every page.
Click it to see:
- Request / Response — headers, parameters, cookies
- Database — every SQL query executed, with timing
- Log — all messages logged during the request
- Config — the full application configuration tree
- Memory / Time — performance metrics per request
This is one of Yii2's best developer experience features. Use it constantly during development.
Exploring Gii
Gii is Yii2's web-based code generator. Visit http://localhost:8080/gii to open it.
You'll see generators for:
- Model Generator — creates Active Record classes from DB tables
- CRUD Generator — creates full create/read/update/delete scaffolding
- Controller Generator — creates controller stubs
- Form Generator — creates form model classes
- Module Generator — creates reusable modules
- Extension Generator — creates installable extensions
You won't use Gii in detail until Post #9, but take a moment to open it and explore the interface. Understanding what Gii generates for you is key to understanding Yii2's conventions.
Common Beginner Mistakes
Pointing the web server at the project root instead of web/
Always set your document root to myapp/web/, not myapp/. If you point at the project root, config files and vendor code become publicly accessible — a serious security risk.
Committing cookieValidationKey to version control
This key protects session cookies from tampering. Generate a unique random string (openssl rand -base64 32) and keep it out of git. Use a local config file or environment variable.
Using YII_DEBUG=true in production
Debug mode exposes detailed error messages including file paths, configuration values, and stack traces. Always set YII_DEBUG=false in production.
Not understanding the runtime/ directory
Yii2 writes logs, cached views, and debug data to runtime/. This directory must be writable by your web server user. If it's not writable, your app will throw errors. Never commit the contents of runtime/ to git.
Forgetting to set file permissions
On Linux/macOS, the web server needs write access to runtime/ and web/assets/ (for published asset bundles):
chmod -R 777 runtime/ web/assets/
# Or better — own them by the web server user
chown -R www-data:www-data runtime/ web/assets/What's Next?
You've installed Yii2, understood the project structure, configured your application, and built your first controller and view. Here's what comes next in the series:
Post #3: Phase 2 — MVC in Yii2 — Go deep on Controllers, Views, Models, and URL management. You'll learn how to build real request/response flows, use layouts, handle redirects and flash messages, and design clean URL rules.
Post #4: Phase 3 — Active Record & Query Builder — Connect to a real database, define Active Record models, run migrations, and query data with relations.
Quick Reference
// Application access
Yii::$app->db // Database connection
Yii::$app->cache // Cache
Yii::$app->request // HTTP request
Yii::$app->response // HTTP response
Yii::$app->user // Auth / current user
Yii::$app->session // Session
Yii::$app->params // Application parameters array
// Path aliases
Yii::getAlias('@app') // /path/to/myapp
Yii::getAlias('@webroot') // /path/to/myapp/web
Yii::getAlias('@web') // http://localhost:8080
// Logging
Yii::info('message', 'category');
Yii::warning('message', 'category');
Yii::error('message', 'category');
// Access params
$adminEmail = Yii::$app->params['adminEmail'];
// Run console command
php yii serve // Start dev server
php yii migrate // Run database migrations
php yii help // List all console commandsSummary
In this post you:
✅ Installed PHP 8.x and Composer
✅ Created a Yii2 Basic project with composer create-project
✅ Mapped out every directory and its purpose
✅ Read and understood the configuration system (web.php, db.php, params.php)
✅ Learned how the service locator works (Yii::$app->component)
✅ Understood Yii2 aliases for path management
✅ Traced the full request lifecycle from browser to response
✅ Built your first controller and views
✅ Enabled pretty URLs
✅ Connected to a database
✅ Explored the Debug Toolbar and Gii
This foundation supports everything that follows. In the next post we'll build on it with the full MVC layer — real controllers with filters, structured views with layouts, and clean URL rules.
Continue to Post #3: MVC in Yii2 →
Back to Yii2 Learning Roadmap
📬 Subscribe to Newsletter
Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.
We respect your privacy. Unsubscribe at any time.
💬 Comments
Sign in to leave a comment
We'll never post without your permission.