Using new PointerProperty with custom property
This is how I do it in the Blender addon for LuxCore:

import bpy
from bpy.props import PointerProperty

def init():
    bpy.types.Material.luxcore = PointerProperty(type=LuxCoreMaterialProps)

class LuxCoreMaterialProps(bpy.types.PropertyGroup):
    node_tree = PointerProperty(name="Node Tree", type=bpy.types.NodeTree)


(The init() function is called in the top-level register() function)
You can then access the node tree like this (example from the Python console):

&gt;&gt;&gt; material = bpy.data.materials['Material']
&gt;&gt;&gt; material.luxcore.node_tree
bpy.data.node_groups['Material']


I think it's a good idea to add all properties specific to an external renderer to a PropertyGroup like "luxcore" or "appleseed" to prevent any conflicts. Cycles does the same thing.

Important

Note that PointerProperties attached to the material are not properly loaded in versions prior to 2.79a RC1: https://developer.blender.org/T53509

See also my notes on PointerProperties in the blenderseed bug tracker for issues with backwards/forwards compatibility: https://github.com/appleseedhq/blenderseed/issues/31