Skip to content
Titanium SDK

Working with data

Written for Titanium SDK 13.4.0 and later

Titanium gives you three places to keep data on the device, and the whole decision is how much of it there is and what shape it has.

Store For Survives an uninstall
Ti.App.Properties Settings and small values No
Ti.Filesystem Files, downloads, generated content No
Ti.Database Rows you query No

None of them survive an uninstall. Anything that must is on a server, and networking is how it gets there.

Properties

Key-value storage for small things: the last tab, a token, whether the user has seen the tour. It is backed by NSUserDefaults on iOS and SharedPreferences on Android, and it is read synchronously.

Ti.App.Properties.setString('lastTab', 'inbox');
Ti.App.Properties.setBool('seenTour', true);

const tab = Ti.App.Properties.getString('lastTab', 'inbox');
const seen = Ti.App.Properties.getBool('seenTour', false);

Every getter takes a default as its second argument. Use it rather than checking hasProperty first, which is a second lookup for the same answer.

There is a setter and getter per type - setString, setInt, setBool, setDouble, setList, setObject - and reading with the wrong one does not convert. Store with setInt and read with getString and you get the default back.

setObject and setList serialise to JSON, so they are for a handful of values, not a collection you keep adding to.

Warning

Properties are not secure storage. They are plain preferences, readable on a rooted or jailbroken device and included in an unencrypted device backup. A token you would mind losing belongs in the keychain or keystore, which is a native module rather than a core API.

Files

Ti.Filesystem addresses directories by purpose, and the purpose decides whether the operating system may delete what you put there.

Directory Use for Backed up
applicationDataDirectory Content the app created and needs Yes
applicationCacheDirectory Anything re-downloadable No, and may be purged
tempDirectory Working files for right now No
resourcesDirectory What you shipped. Read-only n/a
const file = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'notes.txt');
file.write('written on ' + new Date().toISOString());

if (file.exists()) {
  Ti.API.info(file.read().text);
}

getFile takes path segments and joins them, so pass the directory and the name rather than concatenating with a separator yourself.

Putting a cache in applicationDataDirectory is the common mistake: it is backed up, so a 200MB image cache goes into the user's iCloud backup.

A database

Ti.Database is SQLite. Open a database by name and it is created on first use.

const db = Ti.Database.open('notes');

db.execute(`
  CREATE TABLE IF NOT EXISTS notes (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    body TEXT NOT NULL,
    created TEXT NOT NULL
  )
`);

db.execute('INSERT INTO notes (body, created) VALUES (?, ?)', 'First note', new Date().toISOString());
Ti.API.info(`inserted row ${db.lastInsertRowId}`);

const rows = db.execute('SELECT id, body FROM notes ORDER BY id DESC');
while (rows.isValidRow()) {
  Ti.API.info(`${rows.fieldByName('id')}: ${rows.fieldByName('body')}`);
  rows.next();
}
rows.close();
db.close();

Pass values as arguments, never by building the SQL string. The ? placeholders are escaped for you; string concatenation is how an apostrophe in a note becomes a syntax error and how a hostile value becomes an injection.

A result set is a cursor, not an array: walk it with isValidRow() and next(), and close it. Close the database when you are done with it.

executeAsync and executeAllAsync run off the main thread and take a callback. Use them for anything large enough to be noticeable, which on a phone is sooner than you would guess.

Shipping a prepared database

Ti.Database.install copies a .sqlite file out of your resources on first run and opens it, so an app can ship with data already in it.

const db = Ti.Database.install('/data/seed.sqlite', 'notes');

The copy happens once. Changing the shipped file in a later release does not replace a database the user already has, so version your schema and migrate.

Next

Networking and remote data is the other half: getting data in and out over HTTP.

Edit this page on GitHubLast updated Nov 9, 2026