Back to articles list
- 12 minutes read

Coping with the 4Ds of Life: A Self-Storage Data Model

How does the self-storage business work? Why might someone need such a service? And what kind of data model could run it?

Self-storage facilities allow people to rent a space to store their extra belongings. Depending on where you live, you may or may not be familiar with the idea. Personally, I knew that self-storage facilities existed, but I never cared much about them. I simply had no need for such a service. This industry is very popular in the USA and Australia, but it has expanded to Europe and other continents as well.

I guess the reason most people use self-storage has to do with a group of life events known as the “4 Ds”. (No, these are not the same as getting a Nintendo 4DS. ☺) In this article, we’ll analyze how the storage business works and then describe a data model we could use to run this type of company.

Answering the Important Questions

Before we dive into the data model, we should answer a few questions.

  1. What are life’s 4 Ds?

    The 4 Ds usually refer to a group of four life-altering events: dislocation (i.e. moving house), downsizing, divorce, or death. Each of these events often requires that we move our things to a new place.

  2. What are self-storage facilities?

    Self-storage facilities are nothing more than facilities that contain multiple storage units similar to garages. These units can vary in size. For reference, some standard dimensions used for American storage units are 5 feet by 5 feet, 5 feet by 10 feet, 10 feet by 30 feet, etc.

    They are called self-storage units (or sometimes just “storage units”) because people rent them to store their own things.

  3. What is the connection between the 4 Ds and self-storage facilities?

    If you’re dealing with one or more of the 4 Ds, there is a good chance that you’ll need a place to store some extra stuff, at least for a while. Imagine moving to a new city where you don’t yet have a permanent place to stay. If you’re sleeping in a hotel room or a spare room, you’ll need somewhere to store most of your belongings until you get your own place. Based on the amount of stuff you possess, you’ll rent a smaller or a larger storage unit.

    Of course, there are other reasons to rent a storage unit. But for now, we won’t bother with those.

  4. How does self-storage work?

    It’s pretty simple. You come with your stuff, sign a contract for a unit, and store your stuff for a predefined or ongoing period. Maybe you’ll pay regular payments (i.e. a month-to-month contract) or you’ll pay in advance for the whole period (i.e. one payment for an entire year). As long as your payments are made, your stuff is securely stored.

  5. What happens if you don’t pay?

    You’ll be notified of your debt first; you may get one or several notifications. If you don’t pay up, the stuff in your unit may be sold or auctioned off. TV shows like Storage Wars and Auction Hunters demonstrate this process really well. In fact, these two TV shows and others like them have popularized the self-storage industry.

  6. A little history about the self-storage business…

    The history of the modern self-storage industry began in Fort Lauderdale, Florida, USA. In 1958, the Collum family founded the Lauderdale storage facility. Since then, the American self-storage industry has grown to 60,000 facilities. Plus, there are many thousands more across Europe and Australia. And this increases by thousands every year.

  7. And a little more history…

    If we believe legend, the originator of the self-storage concept was an ancient Chinese man called Xiang Lao. (In Chinese, Lao Xiang means someone from the same village or town as you.) Approximately 6,000 years ago, he needed a place to store his valuables. So he fashioned large clay pots and dug them into the ground. He used these pots to store items and he paid guards to watch over them. His “facilities” became popular and many of his neighbors paid him to store their valuables. And thus it all began: with pots and holes in the ground.

The Data Model




The data model consists of five main subject areas:

  • Countries & cities
  • Facilities & units
  • Contracts & invoices
  • Statuses
  • Auctions

We’ll describe each subject area in the same order they are listed.

Section 1: Countries and Cities

Section 1: Countries and Cities

The Countries & cities subject area contains only two simple tables. We’ll use these tables to denote the locations of our storage facilities.

The country table contains a list of UNIQUE country_name attributes that denote where we have storage facilities.

A list of all the cities in all the countries where we operate is stored in the city table. For each city, we’ll store the city_name, the ID of the relevant country, and the postal_code.

Section 2: Facilities and Units

Section 2: Facilities and Units

The Facilities & units subject area contains three tables that are used to describe our facilities as well as all the storage units they contain.

A list of all the facilities we operate is stored in the storage_facility table. For each facility, we’ll store:

  • city_id – A reference to the related city.
  • facility_code – A UNIQUE code we’ll use internally to designate that facility.
  • facility_name – An internal name for that facility. Unlike facility_code, we’ll have a more descriptive value here, something like “Melrose Place Storage Facility”. Although these names will probably be unique, it is not required.
  • address – The physical address of that facility.
  • capacity – The number of storage units in that facility. We could get this information by totaling the number of related storage unit records, but I would like to store this information here as well.

A list of all the different storage unit types is held in the storage_unit_type dictionary. Storage units usually have standard dimensions, but we could define our own dimensions. Also, we may want to add different property attributes, like the kind of lock or door the unit has. For each storage unit type, we’ll store a:

  • type_name – A UNIQUE name used for that unit type.
  • length, width and height – All three dimensions for that storage unit type. Length and width are the two most important dimensions, but height also has a big impact because many people fill their storage unit to its maximum volume.
  • description – An additional field that describes all other details related to that unit type.

Now we’re ready to define all our individual storage units. In the storage_unit table, we’ll denote each storage unit UNIQUELY by a unit_code. The other attributes in this table are:

  • storage_facility_id – The ID of the facility where the unit is located.
  • storage_unit_type_id – References the relevant type ID for that unit.
  • location – A textual description of where the unit is located in the storage facility – e.g. “section A, at the end of the row”.
  • current_status_id – References the status dictionary and denotes the current state of the unit. We’ll explain unit status more in Section 4.
  • price_per_day – What the renter pays per day to use this storage unit. Different units, even of the same type, could have different prices. The facility where the unit is located and the location inside the facility influence the price.

Section 3: Contracts and Invoices

Section 3: Contracts and Invoices

We’ll use the Contracts & invoices subject area to store everything related to our clients and to describe their contracts and obligations.

The renter table contains records of every client we’ve ever done business with. The attributes in this table are:

  • first_name and last_name – The client’s first and last name. If the client is an individual, both of these attributes are NOT NULL. If the client is a business or some other legal entity, these attributes could store the name of their representative or just NULL values.
  • company_name – The name of the company or legal entity. If the client is a private individual, this attribute will be NULL.
  • full_name – The client’s full name (first_name + last_name + company_name). In cases when a client is a private individual, this will be first_name + last_name. For legal entities, it will usually contain only the company_name. In some cases, we may want to store the legal entity’s name and the name of the responsible person in one field. Obviously, that will happen only if we fill all three previously mentioned attributes.
  • phone, mobile, email – The client’s contact information.

All our clients must sign one or more contracts with us. One contract could be signed for one or more storage units. In our model, we’ll save all contract details in the contract table. Contracts are described using the following attributes:

  • renter_id – References the renter (client) who signed that contract.
  • contract_code – A UNIQUE code we’ll use internally to designate that contract.
  • date_signed – The date when the contract was signed.
  • contract_details – All details related to that contract. This attribute is used to describe all contract parameters that can be stored in “free” text format.
  • interval_id – The time interval when the invoices for this contract will be generated (e.g. monthly, yearly). This references the interval table described below.
  • discount_percentage – The discount percentage (if any) we offer the client. Discounts are based on specific client or contract details, such as renting multiple units or being a repeat customer.

The interval table is used to define intervals when the invoices for contracts should be generated. For each interval, we’ll define a UNIQUE interval_name and denote what that interval represents: every X days (daily = “True”); X weeks (weekly = “True”); X months (monthly = “True”); or X years (yearly = “True”). Please note that exactly only one of these four attributes should be active at a time. The last attribute in this table is the “interval”, which defines how many days/weeks/months/years should pass before the next invoice is generated. In the above examples, the X represents the interval attribute.

The last table in this subject area is the invoice table. Invoices may be related to contracts or to auctions, which we will discuss later. For each invoice, we’ll store:

  • issued_by – The entity who issued that invoice. This attribute should contain our company details when we’re issuing an invoice for unit rental. If we auction a unit, we’ll store the winning bidder’s data here.
  • issued_to – Who is paying the invoice; the exact opposite of issued_by.
  • contract_id – The ID of the related contract, if any. If the invoice is related to a rental, there will be a value here; if the invoice is generated for auction purposes, this attribute will contain a NULL value.
  • renter_id – The ID of the relevant renter, when the invoice is related to unit rental.
  • time_created – The exact moment when the invoice was generated.
  • invoice_items – A textual description of all invoice items.
  • invoice_amount – The base amount due, not including any discounts or taxes.
  • discount_percentage – The percent of discount, if any, that is defined in that contract.
  • discount_amount – The discount amount, which is calculated from the invoice_amount and the discount_percentage.
  • tax_percentage and tax_amount – The tax percentage and the total tax amount for that invoice.

Section 4: Statuses

Section 4: Statuses

We’ll define the status of each storage unit separately. That way, we can store a complete history and have better insight into what is going on with units over time. We’ll use three tables to accomplish this.

The status dictionary contains all statuses we could assign to a storage unit. For each status, we’ll define a UNIQUE status_name as well as an occupied value to denote if a storage unit is currently being used or not.

The complete status history is stored in the status_history table. The current status of the unit is stored in the storage_unit.”current_status_id attribute. Each time we modify the current status, we’ll also make changes in the status_history table. We’ll set the end_date of the currently active status and add a new status with the same value in the start_date. Always ensure that two or more status intervals set for the same unit don’t overlap.

The rental_period table is used to define the intervals when units are occupied. Notice that a single contract could be used to rent one or more units; we need to have one record for each unit on the contract. We’ll store:

  • contract_id – The ID of the related contract.
  • storage_unit_id – The relevant unit ID.
  • start_date – The date when the renter starts using the unit.
  • end_date – The date when the renter stops using the unit. This could contain a NULL value if the contract is open-ended, e.g. on a month-to-month basis.
  • price_per_day – How much the rental of that unit is worth on a daily basis. This is the same as the storage_unit.”price_per_day value at the moment the contract was signed.

Section 5: Auctions

Section 5: Auctions

The last subject area in our model is the Auction subject area. Although it looks complex, there are only two tables that we haven’t already mentioned: auction and on_auction. The remaining three tables are copies from other subject areas. They are used here to simplify the model and avoid relations overlapping.

If the renter doesn’t fulfill their contractual obligations, we would send him one or more notifications and requests for payment. If they do not pay their debt to us, we could auction off the contents of their storage unit. This both frees up the unit for new clients and covers our lost income. Storage unit auctions are advertised online and in print and they proceed much like other auctions: people place bids and the highest bid wins. In this case, the bidder buys all the items the unit.

We’ll keep auction details in the auction table. The attributes in the table are:

  • auction_code – A UNIQUE code we’ll use internally for this auction.
  • start_time – The exact time the auction will start.
  • storage_facility_id – The ID of the storage facility where the auction will be held.
  • auction_details – All other details related to that auction.

The final table in our model is the on_auction table. This is where we’ll relate storage units with specific auctions. For each record, we’ll store:

  • auction_id – The ID of the related auction.
  • storage_unit_id – The ID of the related storage unit.
  • opening_bid – The first bid for that unit on that auction.
  • highest_bid – The winning bid for that unit.
  • sold – Denotes if the unit was successfully auctioned off.
  • details – All other details related to the auction of that unit.
  • invoice_id – The ID of the invoice for the sale of this unit, if any.
  • ts – The timestamp when this record was inserted.

What Else?

We’ve described a data model that could be used to manage one or more self-storage facilities. I think that I’ve covered everything important in this model. Do you think we could add something more? Would you change something in this model? Please tell us in the comments section!

go to top