RJ Sites

Como criar Estados e Cidades no Laravel usando a API do IBGE

Crie uma base confiável de estados e municípios brasileiros no Laravel usando dados oficiais do IBGE.

Em muitos projetos Laravel, principalmente sistemas administrativos, ERPs e SaaS, surge a necessidade de trabalhar com Estados e Cidades do Brasil.

O problema é que:

  • cadastrar isso manualmente é inviável
  • seeds estáticos ficam desatualizados
  • copiar dumps da internet não é confiável

Neste tutorial, vou mostrar como criar uma estrutura profissional de Estados e Cidades no Laravel, consumindo diretamente a API oficial e gratuita do IBGE, garantindo dados corretos e atualizados.

Você vai aprender a:

  • criar migrações bem estruturadas
  • definir relacionamentos Eloquent
  • criar um comando Artisan para importar os dados
  • popular o banco com segurança e sem duplicações

📦 O que vamos construir

  • Tabela states
  • Tabela cities
  • Models com relacionamento

Comando Artisan:

php artisan ibge:import-locations

1️⃣ Criando os models e migrations

Vamos começar criando os models já com suas migrations:

php artisan make:model State -m
php artisan make:model City -m

📄 Migration da tabela states

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up(): void
    {
        Schema::create('states', function (Blueprint $table) {
            $table->id();
            $table->string('uf', 2)->unique();              // SP, RJ...
            $table->string('name')->index();                // São Paulo
            $table->unsignedInteger('ibge_id')->unique();   // ID oficial do IBGE
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('states');
    }
};

💡 Por que essas colunas?

  • uf: facilita exibição e filtros
  • ibge_id: garante integridade com dados oficiais
  • unique: evita duplicações
  • index: melhora buscas por nome

📄 Migration da tabela cities

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up(): void
    {
        Schema::create('cities', function (Blueprint $table) {
            $table->id();
            $table->foreignId('state_id')
                ->constrained('states')
                ->cascadeOnDelete();

            $table->string('name')->index();
            $table->unsignedInteger('ibge_id')->unique();
            $table->timestamps();

            // evita cidades duplicadas dentro do mesmo estado
            $table->unique(['state_id', 'name']);
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('cities');
    }
};

▶️ Executando as migrations

php artisan migrate

2️⃣ Criando os models e relacionamentos

🧠 Model State

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class State extends Model
{
    protected $fillable = ['uf', 'name', 'ibge_id'];

    public function cities(): HasMany
    {
        return $this->hasMany(City::class);
    }
}

🧠 Model City

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class City extends Model
{
    protected $fillable = ['state_id', 'name', 'ibge_id'];

    public function state(): BelongsTo
    {
        return $this->belongsTo(State::class);
    }
}

Agora você já pode fazer:

$state->cities;
$city->state;

3️⃣ Criando o comando Artisan para importar do IBGE

Em vez de usar seed fixo, vamos criar um comando reutilizável, que pode ser executado sempre que necessário.

php artisan make:command IbgeImportLocations

📄 Comando IbgeImportLocations

namespace App\Console\Commands;

use App\Models\City;
use App\Models\State;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;

class IbgeImportLocations extends Command
{
    protected $signature = 'ibge:import-locations';
    protected $description = 'Importa estados e cidades do IBGE para o banco local';

    public function handle(): int
    {
        $this->info('Buscando estados no IBGE...');

        $statesResponse = Http::timeout(60)
            ->get('https://servicodados.ibge.gov.br/api/v1/localidades/estados');

        if (! $statesResponse->successful()) {
            $this->error('Falha ao consultar estados no IBGE.');
            return self::FAILURE;
        }

        $states = collect($statesResponse->json())
            ->sortBy('nome')
            ->values();

        foreach ($states as $s) {
            $state = State::updateOrCreate(
                ['ibge_id' => $s['id']],
                ['uf' => $s['sigla'], 'name' => $s['nome']]
            );

            $this->info("Importando cidades de {$state->uf}...");

            $citiesResponse = Http::timeout(120)
                ->get("https://servicodados.ibge.gov.br/api/v1/localidades/estados/{$state->ibge_id}/municipios");

            if (! $citiesResponse->successful()) {
                $this->warn("Falha ao buscar cidades de {$state->uf}. Pulando...");
                continue;
            }

            foreach ($citiesResponse->json() as $c) {
                City::updateOrCreate(
                    ['ibge_id' => $c['id']],
                    [
                        'state_id' => $state->id,
                        'name' => $c['nome'],
                    ]
                );
            }
        }

        $this->info('Importação concluída com sucesso.');
        return self::SUCCESS;
    }
}

4️⃣ Executando a importação

php artisan ibge:import-locations

Ao final você terá:

  • 27 estados
  • mais de 5.500 cidades
  • dados oficiais
  • sem duplicações

✅ Vantagens dessa abordagem

  • 📌 Dados oficiais do IBGE
  • 📌 Comando reutilizável
  • 📌 Evita seeds desatualizados
  • 📌 Fácil manutenção
  • 📌 Pronto para produção

    🧠 Conclusão

    Essa é uma forma simples, robusta e profissional de manter Estados e Cidades no Laravel.

    Você pode usar essa estrutura em:

    • formulários de endereço
    • filtros geográficos
    • cadastros de usuários
    • sistemas administrativos
    • SaaS multi-região

    O que é Git?

    Se você ainda não sabe exatamente o que é, aqui eu te explico de forma simples o que é, pra que serve e como equipes

    Leia mais »