PHPackages                             mcpuishor/linode-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. mcpuishor/linode-laravel

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

mcpuishor/linode-laravel
========================

A Laravel package for Linode integration

v1.0.1(1w ago)040MITPHPPHP ^8.4CI passing

Since Jun 13Pushed 1w agoCompare

[ Source](https://github.com/mcpuishor/linode-laravel)[ Packagist](https://packagist.org/packages/mcpuishor/linode-laravel)[ Docs](https://github.com/mcpuishor/linode-laravel)[ RSS](/packages/mcpuishor-linode-laravel/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (7)Dependencies (8)Versions (13)Used By (0)

Linode Laravel
==============

[](#linode-laravel)

A Laravel package for the [Linode API v4](https://techdocs.akamai.com/linode-api/reference/api). Covers Compute Instances, Managed Databases (MySQL and PostgreSQL) and Regions.

[![Tests](https://github.com/mcpuishor/linode-laravel/actions/workflows/tests.yml/badge.svg)](https://github.com/mcpuishor/linode-laravel/actions/workflows/tests.yml)

> **Upgrading from 0.x?** Read [UPGRADE.md](UPGRADE.md) — 1.0 contains breaking changes, including two bug fixes that change behaviour you may have relied on.

Requirements
------------

[](#requirements)

PackageVersionPHP8.4+Laravel13.0+Installation
------------

[](#installation)

```
composer require mcpuishor/linode-laravel
```

Publish the configuration:

```
php artisan vendor:publish --tag="linode-config"
```

Add your API key to `.env`:

```
LINODE_API_KEY=your-api-key
LINODE_PAGE_SIZE=100   # optional, Linode's maximum is 500
```

Getting a client
----------------

[](#getting-a-client)

```
use Mcpuishor\LinodeLaravel\LinodeClient;

$linode = LinodeClient::make();          // static constructor
$linode = app(LinodeClient::class);      // from the container

LinodeClient::instances()->all();        // or skip the client entirely
```

Listing and pagination
----------------------

[](#listing-and-pagination)

Every list endpoint is paginated. `all()` walks all pages lazily, holding one page in memory at a time:

```
foreach ($linode->instances()->all() as $instance) {
    echo $instance->label;
}
```

It returns a `LazyCollection`, so the usual pipeline works and nothing is fetched until you iterate:

```
$linode->instances()->all()
    ->filter(fn ($i) => $i->status === 'running')
    ->take(10);
```

> A `LazyCollection` re-runs its source each time it is iterated. Call `->collect()` once if you need to traverse the result repeatedly.

When you want a single page and its metadata:

```
$page = $linode->instances()->page(2, pageSize: 50);

$page->data;            // Collection
$page->page;            // 2
$page->pages;           // 7
$page->results;         // 340
$page->hasMorePages();  // true
```

Compute Instances
-----------------

[](#compute-instances)

```
$instances = $linode->instances();

$instances->all();                  // LazyCollection, every page
$instances->page(2);                // one page + metadata
$instances->get(123);               // fetch one, as a ValueObject
$instances->create([...]);
$instances->update(123, [...]);
$instances->delete(123);

$instances->types();                // available plans
$instances->type('g6-standard-1');
$instances->kernels();
$instances->kernel('linode/latest-64bit');
```

### Working with one instance

[](#working-with-one-instance)

`find()` binds an id without calling the API, and everything for that instance hangs off the handle:

```
$server = $linode->instances()->find(123);

$server->get();                      // fetch it
$server->update(['label' => 'web-1']);
$server->delete();
```

**Power**

```
$server->boot();
$server->boot(configId: 456);
$server->reboot();
$server->shutdown();
```

**Lifecycle**

```
$server->resize('g6-standard-4');
$server->resize('g6-standard-4', ['migration_type' => 'warm']);
$server->rebuild('linode/ubuntu24.04', 'a-strong-root-password');
$server->rescue(['sda' => ['disk_id' => 456]]);
$server->clone(['region' => 'eu-west']);
$server->migrate(['region' => 'eu-west']);
$server->mutate();                            // upgrade to newer hardware
$server->resetPassword('a-strong-root-password');
```

**Backups**

```
$server->backups()->all();                    // automatic + snapshot + in-progress
$server->backups()->enable();
$server->backups()->cancel();
$server->backups()->snapshot('pre-deploy');
$server->backups()->find(789);
$server->backups()->restore(789);                              // back onto itself
$server->backups()->restore(789, toLinodeId: 456, overwrite: true);
```

**Disks**

```
$server->disks()->all();
$server->disks()->create(['size' => 81920, 'filesystem' => 'ext4']);

$disk = $server->disks()->find(456);
$disk->get();
$disk->update(['label' => 'root']);
$disk->resize(81920);                         // size in MB
$disk->resetPassword('a-strong-root-password');
$disk->clone(['linode_id' => 789]);
$disk->delete();
```

**Configuration profiles**

```
$server->configs()->all();
$server->configs()->create([...]);

$config = $server->configs()->find(1);
$config->get();
$config->update(['label' => 'boot']);
$config->delete();
```

**Networking**

```
$server->ips();                               // full networking picture
$server->ip('192.0.2.1');
$server->allocateIp(['type' => 'ipv4', 'public' => true]);
$server->updateIp('192.0.2.1', ['rdns' => 'web-1.example.com']);
$server->deleteIp('192.0.2.1');

$server->firewalls();
$server->nodeBalancers();
$server->volumes();
```

**Metrics**

```
$server->stats();              // last 24 hours
$server->stats(2026, 3);       // an archived month
$server->transfer();           // this month
$server->transfer(2026, 3);
```

Managed Databases
-----------------

[](#managed-databases)

Without an engine you get the account-wide view, which lists clusters of every engine:

```
$linode->databases()->all();
$linode->databases()->types();
$linode->databases()->type('g6-standard-1');
$linode->databases()->engines();
$linode->databases()->engine('mysql/8.0.26');
```

Selecting an engine returns a **new** instance scoped to it — the original is left alone:

```
$mysql = $linode->databases()->mysql();
$postgres = $linode->databases()->postgresql();

$mysql->all();
$mysql->get(123);
$mysql->create([
    'label' => 'orders',
    'region' => 'us-east',
    'type' => 'g6-standard-1',
    'engine' => 'mysql/8',
    'cluster_size' => 3,
]);
$mysql->update(123, ['label' => 'orders-primary']);
$mysql->delete(123);
$mysql->config();             // advanced configuration parameters
```

Operations on one cluster use `find()`, the same as instances:

```
$db = $linode->databases()->mysql()->find(123);

$db->get();
$db->update(['allow_list' => ['192.0.2.1/32']]);
$db->suspend();
$db->resume();
$db->patch();                 // apply maintenance patches
$db->credentials();
$db->resetCredentials();
$db->ssl();                   // CA certificate for the selected engine
$db->delete();
```

Operations requiring an engine throw `EngineNotSelectedException` when one has not been chosen.

**PostgreSQL connection pools** (PostgreSQL only; calling this on MySQL throws):

```
$pools = $linode->databases()->postgresql()->find(123)->connectionPools();

$pools->all();
$pools->get('reporting');
$pools->create(['name' => 'reporting', 'mode' => 'transaction', 'size' => 25]);
$pools->update('reporting', ['size' => 50]);
$pools->delete('reporting');
```

Regions
-------

[](#regions)

```
$linode->regions()->all();
$linode->regions()->get('us-east');
$linode->regions()->availability();          // every region
$linode->regions()->availability('us-east'); // one region
```

Working with responses
----------------------

[](#working-with-responses)

API responses come back as `ValueObject`, an immutable view over the decoded payload. Attributes are read as properties, and nested objects stay navigable:

```
$instance = $linode->instances()->get(123);

$instance->label;            // "web-1"
$instance->specs->vcpus;     // nested objects
$instance->tags;             // lists stay plain arrays
$instance->toArray();
$instance->toJson();
json_encode($instance);
```

Reading an attribute that is not in the response throws `UnknownAttributeException`, so typos fail loudly rather than reading as `null`:

```
$instance->lable;
// Unknown attribute [lable] ... Did you mean [label]?

```

For genuinely optional attributes:

```
$instance->has('image');            // true even when the value is null
$instance->get('image', 'none');    // read with a default
$instance->image ?? 'none';         // isset()/?? work and never throw
$instance->lenient()->image;        // null for anything missing
```

`ValueObject` is intentionally not a generated DTO. Linode adds response fields continuously, and passing them straight through means you can read a new field the day it ships rather than waiting for a release of this package.

### Storing responses on a model

[](#storing-responses-on-a-model)

`AsValueObject` casts a JSON column to and from a `ValueObject`:

```
use Mcpuishor\LinodeLaravel\Casts\AsValueObject;

class Server extends Model
{
    protected $casts = [
        'linode_payload' => AsValueObject::class,
    ];
}
```

Error handling
--------------

[](#error-handling)

Everything the package throws extends `LinodeException`:

```
LinodeException (abstract)
├── LinodeApiException           the API returned an error response
├── EngineNotSelectedException   a database engine was required but not chosen
├── ResourceNotFoundException    a resource was expected but came back empty
├── UnexpectedResponseException  a success response the package cannot use
└── UnknownAttributeException    an attribute was read that does not exist

```

```
use Mcpuishor\LinodeLaravel\Exceptions\LinodeApiException;

try {
    $linode->instances()->get(123);
} catch (LinodeApiException $e) {
    $e->getResponse();    // the underlying Illuminate HTTP response
    $e->getErrorData();   // the API's `errors` array
    $e->getCode();        // the HTTP status code
}
```

Direct API access
-----------------

[](#direct-api-access)

For endpoints the package does not wrap yet, use the transport directly. It handles the base URL, API version, authentication and error translation:

```
use Mcpuishor\LinodeLaravel\Transport;

$transport = app(Transport::class);

$transport->get('account/events', ['page' => 1]);
$transport->post('account/tags', ['label' => 'production']);
$transport->put('account/settings', [...]);
$transport->delete('account/tags/production');
```

Testing
-------

[](#testing)

```
composer test
composer test:unit
composer test:feature
composer test:coverage
```

The suite is fully offline: `tests/TestCase.php` calls `Http::preventStrayRequests()`, so any request that is not explicitly faked fails the test rather than reaching the network.

License
-------

[](#license)

MIT. See [LICENSE.md](LICENSE.md).

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance98

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity62

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~83 days

Recently: every ~104 days

Total

6

Last Release

7d ago

Major Versions

v0.2.1 → v1.0.02026-08-03

PHP version history (2 changes)v0.0.1PHP ^8.3

v1.0.0PHP ^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/f68447628fda07406fb838fc490d8935d415088a93ec70584f59db2f719637c4?d=identicon)[mcpuishor](/maintainers/mcpuishor)

---

Top Contributors

[![mcpuishor](https://avatars.githubusercontent.com/u/40750444?v=4)](https://github.com/mcpuishor "mcpuishor (27 commits)")

---

Tags

laravelcloudapi clientakamailinode

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/mcpuishor-linode-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/mcpuishor-linode-laravel/health.svg)](https://phpackages.com/packages/mcpuishor-linode-laravel)
```

###  Alternatives

[renatomarinho/laravel-page-speed

Laravel Page Speed

2.5k1.7M11](/packages/renatomarinho-laravel-page-speed)[emargareten/inertia-modal

Inertia Modal is a Laravel package that lets you implement backend-driven modal dialogs for Inertia apps.

90157.6k](/packages/emargareten-inertia-modal)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)[tomshaw/electricgrid

A feature-rich Livewire package designed for projects that require dynamic, interactive data tables.

119.8k](/packages/tomshaw-electricgrid)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
